问题描述
如果我导入了 System.Linq
,我可以在以下调用中使用 this ToArray overload:
var x = "foo".ToArray();
和 x
被分配了一个 char[]
,其中三个元素是字符串 "foo"
中的字符。然后,如果我在范围内添加自定义扩展方法:
public static T[] ToArray<T>(this T toConvert) => new[] { toConvert };
编译器默默地改变了主意,x
变成了一个 string[]
,其中一个元素是字符串 "foo"
。
为什么编译器没有抱怨歧义?我知道一些看似模棱两可的情况会由编译器自动解决而不会出错,但我找不到关于此类情况的任何文档或参考资料。基本上,似乎将 string
视为 string
而不是 char
的隐式数组似乎是首选行为...
解决方法
您引用的第一个扩展方法:
public static TSource[] ToArray<TSource> (this System.Collections.Generic.IEnumerable<TSource> source);
将 IEnumerable<TSource>
转换为数组(泛型接口)。
你做的第二种扩展方法:
public static T[] ToArray<T>(this T toConvert) => new[] { toConvert };
将任何 T 对象转换为单个对象数组。由于这是一个没有接口的泛型类型,因此它优于采用具有泛型类型的接口的扩展方法。本质上,与具有泛型类型的接口相比,应用扩展是潜在类型的更大覆盖面。编译器更喜欢匹配扩展方法的具体类型,而不是匹配的接口。
C# 语言规范,向下大约 60% 找到 Method Overloading
:
https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/introduction
VB 版本,虽然主要适用于 C#: https://docs.microsoft.com/en-us/dotnet/visual-basic/reference/language-specification/overload-resolution