使用.NET 4,我对编译器无法解决下面示例中的第一个方法调用感到困惑。
using System;
namespace MethodResolutionTest
{
class Program
{
static void Main(string[] args)
{
NonGeneric foo = null;
// ambiguous
foo.Ext1(x => new NonGeneric());
// resolves to first Ext1
foo.Ext1(x => new NonGeneric(), 1);
// resolves to first Ext2
foo.Ext2(x => new NonGeneric());
// resolves to first Ext2
foo.Ext2(x => new NonGeneric(), 1);
// resolves to second Ext2
foo.Ext2(x => "foo");
// resolves to second Ext2
foo.Ext2(x => "foo", 1);
// resolves to first Ext3
foo.Ext3(x => new NonGeneric());
// resolves to first Ext3
foo.Ext3(x => new NonGeneric(), 1);
// resolves to second Ext3
foo.Ext3(x => "foo");
// resolves to second Ext3
foo.Ext3(x => "foo", 1);
}
}
public class NonGeneric
{
}
public class Generic<T> : NonGeneric
{
}
public static class Extensions1
{
public static NonGeneric Ext1(this NonGeneric first, Func<NonGeneric, NonGeneric> getNext, int i = 0)
{
return null;
}
public static Generic<TNext> Ext1<TNext>(this NonGeneric first, Func<NonGeneric, TNext> getNext, int i = 0, string s = null)
{
return null;
}
}
// only difference between Extensions2 and Extensions1 is that the second overload no longer has a default string parameter
public static class Extensions2
{
public static NonGeneric Ext2(this NonGeneric first, Func<NonGeneric, NonGeneric> getNext, int i = 0)
{
return null;
}
public static Generic<TNext> Ext2<TNext>(this NonGeneric first, Func<NonGeneric, TNext> getNext, int i = 0)
{
return null;
}
}
// Extensions3 explicitly defines an overload that does not default the int parameter
public static class Extensions3
{
public static NonGeneric Ext3(this NonGeneric first, Func<NonGeneric, NonGeneric> getNext)
{
return Ext3(first, getNext, default(int));
}
public static NonGeneric Ext3(this NonGeneric first, Func<NonGeneric, NonGeneric> getNext, int i = 0)
{
return null;
}
public static Generic<TNext> Ext3<TNext>(this NonGeneric first, Func<NonGeneric, TNext> getNext, int i = 0)
{
return null;
}
}
}
有人可以对此有所了解吗?我怀疑除了修改我的API以帮助编译器之外我没有其他的方法(如上面Extensions3
所述),但是如果有更容易/更好的方式,那么我很乐意听到它。
答案 0 :(得分:1)
这是不明确的,因为在第二个Ext1
扩展方法中有两个可选参数。因为在第一次调用中省略了这两个参数,所以编译器不知道您要使用哪个参数。
来自C# 4.0 Language Specification:
§7.5.3重载决议:
给定适用的候选函数成员集,找到该集合中的最佳函数成员。如果集合只包含一个函数成员,那么该函数成员是最好的函数成员。否则,最佳函数成员是一个函数成员,它比给定参数列表中的所有其他函数成员更好,前提是使用§7.5.3.2中的规则将每个函数成员与所有其他函数成员进行比较。如果没有一个函数成员优于所有其他函数成员,那么函数成员调用是不明确的,并且发生绑定时错误。
此外,在§7.5.3.2更好的功能成员:
下从参数列表中删除没有相应参数的可选参数
这意味着当您省略方法调用中的最后两个参数并推断出NonGeneric
类型时(阅读§7.5.2下的类型推断),两种方法都如下所示:
Ext1(this NonGeneric first, Func<NonGeneric, NonGeneric> getNext)
因此,他们会模棱两可......
我建议阅读§7.5.3.2甚至整个规范的§7.5.3以获取更多信息。
解决方案是更改方法声明或完全删除第一个重载,然后让第二个重载:)