F #: как получить доступ к конкретной перегрузке метода объекта Dotnet в качестве объекта первого класса

Я могу сделать это (F # FSI):

let o = Object()
let m = o.GetHashCode;; //[1]
val o : Object
val m : (unit -> int)

что делает метод GetHashCode доступным и вызываемым как первоклассную функцию в привязке m:

m ();;
val it : int = 12345678

Как бы я это сделал, если бы для рассматриваемого метода существовала перегрузка, скажем, дополнительная Object.GetHashCode(int whateverParameter)? Теперь я могу получить только «первый» (самый короткий?) метод. Могу ли я предоставить дополнительную информацию о типе параметра в вызове 1, чтобы указать, какую перегрузку я хочу?

ИЗМЕНИТЬ

Спасибо за ваш вклад до сих пор. Аннотации типов кажутся правильным выбором. Хотя для моего более сложного примера я все еще не могу понять, как это правильно сделать.

Вот конкретные сигнатуры методов того типа, с которым я имею дело (он взят с сайта octokit.net библиотека, поэтому вам нужно что-то вроде #r "nuget:include=Octokit" в fsi [с /langversion:preview]).

Я заинтересован в получении конкретной перегрузки GetAllForRepository, кстати, первой в списке: GetAllForRepository(string, string).

open Octokit
let client = GitHubClient(...)
client.Issue.GetType().GetMethods()
|> Seq.filter (fun methodInfo -> methodInfo.Name.StartsWith("GetAllForRepository"))
|> Seq.map (fun methodInfo -> (methodInfo.GetParameters(), methodInfo.ReturnType))
|> Seq.map (fun (parameterInfos, returnType) ->
    (parameterInfos |> Seq.map (fun parameterInfo -> parameterInfo.ParameterType.FullName), returnType.FullName))

val it : seq<seq<string> * string> =
  seq
    [(seq ["System.String"; "System.String"],
      "System.Threading.Tasks.Task`1[[System.Collections.Generic.IReadOnlyList`1[[Octokit.Issue, Octokit, Version=0.48.0.0, Culture=neutral, PublicKeyToken=null]], System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]]");
     (seq ["System.Int64"],
      "System.Threading.Tasks.Task`1[[System.Collections.Generic.IReadOnlyList`1[[Octokit.Issue, Octokit, Version=0.48.0.0, Culture=neutral, PublicKeyToken=null]], System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]]");
     (seq ["System.String"; "System.String"; "Octokit.ApiOptions"],
      "System.Threading.Tasks.Task`1[[System.Collections.Generic.IReadOnlyList`1[[Octokit.Issue, Octokit, Version=0.48.0.0, Culture=neutral, PublicKeyToken=null]], System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]]");
     (seq ["System.Int64"; "Octokit.ApiOptions"],
      "System.Threading.Tasks.Task`1[[System.Collections.Generic.IReadOnlyList`1[[Octokit.Issue, Octokit, Version=0.48.0.0, Culture=neutral, PublicKeyToken=null]], System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]]");
     (seq ["System.String"; "System.String"; "Octokit.RepositoryIssueRequest"],
      "System.Threading.Tasks.Task`1[[System.Collections.Generic.IReadOnlyList`1[[Octokit.Issue, Octokit, Version=0.48.0.0, Culture=neutral, PublicKeyToken=null]], System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]]");
     (seq ["System.Int64"; "Octokit.RepositoryIssueRequest"],
      "System.Threading.Tasks.Task`1[[System.Collections.Generic.IReadOnlyList`1[[Octokit.Issue, Octokit, Version=0.48.0.0, Culture=neutral, PublicKeyToken=null]], System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]]");
     (seq
        ["System.String"; "System.String"; "Octokit.RepositoryIssueRequest";
         "Octokit.ApiOptions"],
      "System.Threading.Tasks.Task`1[[System.Collections.Generic.IReadOnlyList`1[[Octokit.Issue, Octokit, Version=0.48.0.0, Culture=neutral, PublicKeyToken=null]], System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]]");
     (seq
        ["System.Int64"; "Octokit.RepositoryIssueRequest";
         "Octokit.ApiOptions"],
      "System.Threading.Tasks.Task`1[[System.Collections.Generic.IReadOnlyList`1[[Octokit.Issue, Octokit, Version=0.48.0.0, Culture=neutral, PublicKeyToken=null]], System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]]")]

Теперь самая короткая подпись принимает один параметр int64:

let m = client.Issue.GetAllForRepository;;
val m :
  (int64 ->
     System.Threading.Tasks.Task<System.Collections.Generic.IReadOnlyList<Octokit.Issue>>)

Я могу явно объявить подпись и получить тот же метод:

let m: (int64 -> System.Threading.Tasks.Task<System.Collections.Generic.IReadOnlyList<Octokit.Issue>>) = client.Issue.GetAllForRepository;;
val m :
  (int64 ->
     System.Threading.Tasks.Task<System.Collections.Generic.IReadOnlyList<Octokit.Issue>>)

Но доступ к версии (string, string) дает мне:

let m: (string -> string -> System.Threading.Tasks.Task<System.Collections.Generic.IReadOnlyList<Octokit.Issue>>) = client.Issue.GetAllForRepository;;

  let m: (string -> string -> System.Threading.Tasks.Task<System.Collections.Generic.IReadOnlyList<Octokit.Issue>>) = client.Issue.GetAllForRepository;;
  --------------------------------------------------------------------------------------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

stdin(33,117): error FS0193: Type constraint mismatch. The type
    'string'
is not compatible with type
    'int64'

Аналогичная ошибка возникает при попытке доступа к любой другой перегрузке с более чем одним параметром:

let m: (int64 -> Octokit.RepositoryIssueRequest -> System.Threading.Tasks.Task<System.Collections.Generic.IReadOnlyList<Octokit.Issue>>) = client.Issue.GetAllForRepository;;

  let m: (int64 -> Octokit.RepositoryIssueRequest -> System.Threading.Tasks.Task<System.Collections.Generic.IReadOnlyList<Octokit.Issue>>) = client.Issue.GetAllForRepository;;
  -------------------------------------------------------------------------------------------------------------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

stdin(37,140): error FS0001: This expression was expected to have type
    'Octokit.RepositoryIssueRequest -> System.Threading.Tasks.Task<System.Collections.Generic.IReadOnlyList<Octokit.Issue>>'
but here has type
    'System.Threading.Tasks.Task<System.Collections.Generic.IReadOnlyList<Octokit.Issue>>'
let m: (int64 -> Octokit.RepositoryIssueRequest -> Octokit.ApiOptions -> System.Threading.Tasks.Task<System.Collections.Generic.IReadOnlyList<Octokit.Issue>>) = client.Issue.- GetAllForRepository;;

  let m: (int64 -> Octokit.RepositoryIssueRequest -> Octokit.ApiOptions -> System.Threading.Tasks.Task<System.Collections.Generic.IReadOnlyList<Octokit.Issue>>) = client.Issue.GetAllForRepository;;
  -----------------------------------------------------------------------------------------------------------------------------------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

stdin(36,162): error FS0001: This expression was expected to have type
    'Octokit.RepositoryIssueRequest -> Octokit.ApiOptions -> System.Threading.Tasks.Task<System.Collections.Generic.IReadOnlyList<Octokit.Issue>>'
but here has type
    'System.Threading.Tasks.Task<System.Collections.Generic.IReadOnlyList<Octokit.Issue>>'

Итак, я делаю что-то неправильно в отношении аннотаций типов?


person Christian    schedule 11.01.2021    source источник
comment
Когда я пытаюсь назначить метод с перегрузкой переменной, я получаю предложение Может потребоваться аннотация типа. — вы пытались сделать именно это?   -  person UnholySheep    schedule 11.01.2021
comment
@Christian Добро пожаловать в сообщество F#!   -  person Scott Hutchinson    schedule 11.01.2021
comment
Это действительно работает для простых случаев, таких как let m: char -> int = "Hello".IndexOf;;, выбирая System.String.IndexOf(char) вместо System.String.IndexOf(string). А вот сигнатуры предполагаемых мною методов (из библиотеки octokit.net) посложнее, вроде Task<IReadOnlyList<Issue>> GetAllForRepository(string owner, string name). Возможно, это связано с возвращаемым значением Task<...>.   -  person Christian    schedule 11.01.2021
comment
Вы пробовали m: ((string * string) -> System.Threading.Tasks.Task<System.Collections.Generic.IReadOnlyList<Octokit.Issue>>)?   -  person Mark Pattison    schedule 13.01.2021


Ответы (2)


В ответ на ваше редактирование вход метода - string * string, а не string -> string (т.е. без каррирования или с карри), поэтому я думаю, что это сработает:

let m : (string * string -> _) = client.Issue.GetAllForRepository
person brianberns    schedule 13.01.2021
comment
Большое спасибо всем вам, но особенно @brianberns за помощь в моей конкретной глупости! - person Christian; 14.01.2021
comment
Совсем не дура. К карри нужно время, чтобы привыкнуть. Рад помочь. - person brianberns; 14.01.2021

Да, аннотация типа позволит вам выбрать нужное переопределение метода:

type MyClass() =
    member __.MyMethod() = 1
    member __.MyMethod(x : int) = 2

let o = MyClass()
let m1 : (unit -> int) = o.MyMethod
let m2 : (int -> int) = o.MyMethod
printfn "%A" <| m1 ()
printfn "%A" <| m2 0
person brianberns    schedule 11.01.2021
comment
Спасибо @brianberns. Это работает для «простых» случаев, к сожалению, не для моего реального примера. Я расширил исходный вопрос. - person Christian; 13.01.2021