为啥编译器选择字符串而不是隐式字符数组的扩展方法?

Posted

技术标签:

【中文标题】为啥编译器选择字符串而不是隐式字符数组的扩展方法?【英文标题】:Why does the compiler pick the extension method on string over implicit char array?为什么编译器选择字符串而不是隐式字符数组的扩展方法? 【发布时间】:2020-12-30 16:07:11 【问题描述】:

如果我导入了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 的隐式数组似乎是首选行为...

【问题讨论】:

寻呼 Jon Skeet 博士 :) "foo" 的静态类型为 stringT as string 是比T as IEnumerable&lt;char&gt; 在先转换后与静态类型的更具体匹配。但斯基特博士可以更好地解释它。 ToCharArray 是你想要的,但 madreflection 有它适合扩展方法。 @jjxtra 对,问题不在于最佳实践,而在于编译器行为。 @jjxtra 也感谢您的编辑,我删除了 this 以确保我的示例正确。 【参考方案1】:

你引用的第一个扩展方法:

public static TSource[] ToArray<TSource> (this System.Collections.Generic.IEnumerable<TSource> source);

IEnumerable&lt;TSource&gt; 转换为数组(泛型接口)。

你做的第二种扩展方法:

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

C# 重载解析: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-7.3/improved-overload-candidates

VB 版本,虽然主要适用于 C#: https://docs.microsoft.com/en-us/dotnet/visual-basic/reference/language-specification/overload-resolution

【讨论】:

您是否可以指出一些文档来支持这种行为?就像我说的,我什么都找不到。 添加了答案底部的链接 很抱歉,指向 Visual Basic 参考的链接并没有太大帮助。这篇文章使用了特定于语言的关键字,例如AddressOf,这至少会让懂这两种语言的人感到厌烦,而让完全不懂 VB 的人完全困惑。肯定有使用 C# 的参考吗? 我也添加了一个更短的 C# 文档。 VB 代码示例不太重要,分辨率点是重要的位。 还添加了 C# 语言规范,向下滚动约 60% 以找到方法分辨率。

以上是关于为啥编译器选择字符串而不是隐式字符数组的扩展方法?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 UIActionSheet init 方法接受字符串数组而不是 NSString

为啥这里不发生隐式转换?

为啥扩展语法会将我的字符串转换为数组?

为啥我们必须通过请求对数组而不是对象进行字符串化?

为啥 ASP.NET MVC HttpFileCollection 会返回字符串数组而不是 HttpPostedFile 集合?

为啥一个空数组等于一个空字符串,而不是 javascript 中的另一个空数组? [复制]