【问题标题】: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 以确保我的示例正确。

标签: c# .net string char ambiguity


【解决方案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 Overloadinghttps://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% 以找到方法分辨率。
猜你喜欢
  • 1970-01-01
  • 2019-10-01
  • 2010-12-16
  • 1970-01-01
  • 1970-01-01
  • 2011-03-05
  • 2019-10-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多