gpt4 book ai didi

F# 方法重载解析不如 C# 智能?

转载 作者:行者123 更新时间:2023-12-04 14:47:05 26 4
gpt4 key购买 nike

说,我有

member this.Test (x: 'a) = printfn "generic"
1
member this.Test (x: Object) = printfn "non generic"
2

如果我在 C# 中调用它
var a = test.Test(3);         // calls generic version
var b = test.Test((object)3); // calls non generic version
var c = test.Test<object>(3); // calls generic version

然而,在 F#
let d = test.Test(3);  // calls non generic version
let e = test.Test<int>(3); // calls generic version

所以我必须添加类型注释才能获得正确的重载方法。这是真的?如果是这样,那么既然已经推断出参数类型,为什么 F# 不会自动正确解析? (无论如何,F# 的重载解析顺序是什么?总是偏爱 Object 而不是它的继承类?)

如果一个方法同时具有两个重载,其中一个将参数设为 Object,则有点危险。 type 而另一个是泛型​​的,并且都返回相同的类型。 (就像在这个例子中,或者在单元测试中 Assert.AreEqual),因为那么我们很可能在没有注意到的情况下得到错误的重载(不会是任何编译器错误)。不会有问题吗?

更新:

有人可以解释一下
  • 为什么 F# 可以解析 Assert.AreEqual(3, 5)Assert.AreEqual(Object a, Object b)但不是 Assert.AreEqual<T>(T a, T b)
  • 但 F# 解析 Array.BinarySearch([|2;3|], 2)BinarySearch<T>(T[]array, T value)但不是 BinarySearch(Array array, Object value)
  • 最佳答案

    F# Method overload resolution not as smart as C#?



    我不认为这是真的。方法重载使类型推断更加困难。 F# 具有合理的权衡,使方法重载可用和类型推断尽可能强大。

    当您将值传递给函数/方法时,F# 编译器会自动将其向上转换为适当的类型。这在许多情况下都很方便,但有时也会令人困惑。

    在您的示例中, 3已上传到 obj类型。这两种方法都适用,但选择了更简单(非通用)的方法。

    Section 14.4 Method Application Resolution在规范中很清楚地指定了重载规则:

    1) Prefer candidates whose use does not constrain the use of a user-introduced generic type annotation to be equal to another type.

    2) Prefer candidates that do not use ParamArray conversion. If two candidates both use ParamArray conversion with types pty1 and pty2, and pty1 feasibly subsumes pty2, prefer the second; that is, use the candidate that has the more precise type.

    3) Prefer candidates that do not have ImplicitlyReturnedFormalArgs.

    4) Prefer candidates that do not have ImplicitlySuppliedFormalArgs.

    5) If two candidates have unnamed actual argument types ty11...ty1n and ty21...ty2n, and each ty1i either

    a. feasibly subsumes ty2i, or

    b. ty2i is a System.Func type and ty1i is some other delegate type, then prefer the second candidate. That is, prefer any candidate that has the more specific actual argument types, and consider any System.Func type to be more specific than any other delegate type.

    6) Prefer candidates that are not extension members over candidates that are.

    7) To choose between two extension members, prefer the one that results from the most recent use of open.

    8) Prefer candidates that are not generic over candidates that are generic—that is, prefer candidates that have empty ActualArgTypes.



    我认为创建明确的重载方法是用户的责任。您始终可以查看推断类型以查看您是否正确执行它们。例如,您的修改版本没有歧义:
    type T() =
    member this.Test (x: 'a) = printfn "generic"; 1
    member this.Test (x: System.ValueType) = printfn "non-generic"; 2

    let t = T()
    let d = t.Test(3) // calls non-generic version
    let e = t.Test(test) // call generic version

    更新:

    它归结为一个核心概念, covariance . F# 不支持数组、列表、函数等的协变。确保类型安全通常是一件好事(请参阅 this example )。

    所以很容易解释为什么 Array.BinarySearch([|2;3|], 2)已解析为 BinarySearch<T>(T[] array, T value) .这是关于函数参数的另一个示例,其中
    T.Test((fun () -> 2), 2)

    解决了
    T.Test(f: unit -> 'a, v: 'a)

    但不是
    T.Test(f: unit -> obj, v: obj)

    关于F# 方法重载解析不如 C# 智能?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14616462/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com