gpt4 book ai didi

c# - 如何解释这个 "call is ambiguous"错误?

转载 作者:行者123 更新时间:2023-12-03 09:27:38 25 4
gpt4 key购买 nike

问题

考虑这两个扩展方法,它们只是来自任何类型的简单映射 T1T2 ,加上一个重载来流畅地映射 Task<T> :

public static class Ext {
public static T2 Map<T1, T2>(this T1 x, Func<T1, T2> f)
=> f(x);
public static async Task<T2> Map<T1, T2>(this Task<T1> x, Func<T1, T2> f)
=> (await x).Map(f);
}

现在,当我使用第二个重载映射到引用类型时......

var a = Task
.FromResult("foo")
.Map(x => $"hello {x}"); // ERROR

var b = Task
.FromResult(1)
.Map(x => x.ToString()); // ERROR

...我收到以下错误:

CS0121: The call is ambiguous between the following methods or properties: 'Ext.Map(T1, Func)' and 'Ext.Map(Task, Func)'



映射到值类型工作正常:

var c = Task
.FromResult(1)
.Map(x => x + 1); // works

var d = Task
.FromResult("foo")
.Map(x => x.Length); // works

但只要映射实际使用输入产生输出:

var e = Task
.FromResult(1)
.Map(_ => 0); // ERROR

问题

任何人都可以向我解释这里发生了什么吗?我已经放弃为这个错误寻找可行的解决方案,但至少我想了解这个困惑的根本原因。

补充说明

到目前为止,我发现了三个在 my use case 中 Not Acceptable 解决方法。 .首先是指定 Task<T1>.Map<T1,T2>()的类型参数明确地:

var f = Task
.FromResult("foo")
.Map<string, string>(x => $"hello {x}"); // works

var g = Task
.FromResult(1)
.Map<int, int>(_ => 0); // works

另一个解决方法是不使用 lambdas:

string foo(string x) => $"hello {x}";
var h = Task
.FromResult("foo")
.Map(foo); // works

第三个选项是限制映射到内函数(即 Func<T, T> ):

public static class Ext2 {
public static T Map2<T>(this T x, Func<T, T> f)
=> f(x);
public static async Task<T> Map2<T>(this Task<T> x, Func<T, T> f)
=> (await x).Map2(f);
}

created a .NET Fiddle您可以自己尝试上述所有示例。

最佳答案

根据 C# 规范,Method invocations ,接下来的规则用于考虑泛型方法 F作为方法调用的候选者:

  • Method has the same number of method type parameters as were supplied in the type argument list,

    and

  • Once the type arguments are substituted for the corresponding method type parameters, all constructed types in the parameter list of F satisfy their constraints (Satisfying constraints), and the parameter list of F is applicable with respect to A (Applicable function member). A - optional argument list.



表达用
Task.FromResult("foo").Map(x => $"hello {x}");

两种方法
public static T2 Map<T1, T2>(this T1 x, Func<T1, T2> f);
public static async Task<T2> Map<T1, T2>(this Task<T1> x, Func<T1, T2> f);

满足这些要求:
  • 它们都有两个类型参数;
  • 他们构建的变体
    // T2 Map<T1, T2>(this T1 x, Func<T1, T2> f)
    string Ext.Map<Task<string>, string>(Task<string>, Func<Task<string>, string>);

    // Task<T2> Map<T1, T2>(this Task<T1> x, Func<T1, T2> f)
    Task<string> Ext.Map<string, string>(Task<string>, Func<string, string>);

  • 满足类型约束(因为 Map 方法没有类型约束)并且根据可选参数适用(因为 Map 方法也没有可选参数)。 注:使用类型推断来定义第二个参数(lambda 表达式)的类型。

    因此,在这一步,算法将这两种变体都视为方法调用的候选者。对于这种情况,它使用重载解析来确定哪个候选更适合调用。规范的话:

    The best method of the set of candidate methods is identified using the overload resolution rules of Overload resolution. If a single best method cannot be identified, the method invocation is ambiguous, and a binding time error occurs. When performing overload resolution, the parameters of a generic method are considered after substituting the type arguments (supplied or inferred) for the corresponding method type parameters.



    表达
    // I intentionally wrote it as static method invocation.
    Ext.Map(Task.FromResult("foo"), x => $"hello {x}");

    可以使用 Map 方法的构造变体以下一种方式重写:
    Ext.Map<Task<string>, string>(Task.FromResult("foo"), (Task<string> x) => $"hello {x}");
    Ext.Map<string, string>(Task.FromResult("foo"), (string x) => $"hello {x}");

    重载解析使用 Better function member算法来定义这两种方法中的哪一种更适合方法调用。

    这个算法我看了好几遍还没找到算法可以定义方法的地方 Exp.Map<T1, T2>(Task<T1>, Func<T1, T2>)作为考虑方法调用的更好方法。在这种情况下(当无法定义更好的方法时)会发生编译时错误。

    总结:
  • 方法调用算法将两种方法都视为候选方法;
  • 更好的函数成员算法无法定义更好的调用方法。


  • 另一种帮助编译器选择更好方法的方法(就像您在其他解决方法中所做的那样):
    // Call to: T2 Map<T1, T2>(this T1 x, Func<T1, T2> f);
    var a = Task.FromResult("foo").Map( (string x) => $"hello {x}" );

    // Call to: async Task<T2> Map<T1, T2>(this Task<T1> x, Func<T1, T2> f);
    var b = Task.FromResult(1).Map( (Task<int> x) => x.ToString() );

    现在第一个类型参数 T1明确定义并且不会出现歧义。

    关于c# - 如何解释这个 "call is ambiguous"错误?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60754529/

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