【问题标题】:Why I don't get syntax error in this sample code?为什么我在此示例代码中没有出现语法错误?
【发布时间】:2016-07-29 22:28:13
【问题描述】:

刚刚尝试了一些 C# Lookup 集合的基础知识,发现这个简单的示例编译得很好,即使是 IGrouping 接口也应该将 TElement 设置为 int。

string txt = "Hello world!";
ILookup<char, int> occurrences = Enumerable.Range(0, txt.Length).ToLookup(i => txt[i], i => i);

foreach (IGrouping<char, string> values in occurrences)
    Console.WriteLine($"{values.Key}: {string.Join(", ", values)}");

显然,我在无效演员表上遇到运行时错误。但我预计,这适用于编译器......

【问题讨论】:

  • @PeterDuniho:那我们可以接受this question and these answers 吗?那是字面意思。是的,虽然title很奇怪,但问题和语义/意思/..是一样的。
  • @Quetzalcoatl:好多了,是的……这似乎更像这个问题。我认为 Scott 在他关于协方差的业务的回答接近尾声时有点混乱,但除此之外,这是本问答的合理复制。

标签: c# casting syntax-error igrouping


【解决方案1】:

这似乎是编译器使用的规则:

如果编译器可以看到值类型或密封类没有 实现或继承程序员试图强制转换的类型 to/from,强制转换在编译时是非法的。

(感谢 Jeppe Stig Nielsen 在 cmets 中提到这一点。)

如果您使用以下任一选项而不是示例中的 XXXX,则这是编译 foreach (XXXX values in occurrences) 的结果。注意occurrences 的类型是ILookup&lt;char, int&gt;,它派生自IGrouping&lt;char, int&gt;

  • public class MyClass { } 编译
  • public sealed class MyClass { } 编译时错误
  • public sealed class MyClass : IGrouping&lt;char, int&gt; {...} 编译
  • public sealed class MyClass : IGrouping&lt;char, string&gt; {...} 编译时错误
  • public struct MyStruct {} 编译时错误
  • public struct MyStruct : IGrouping&lt;char, string&gt; {...} 编译时错误
  • public struct MyStruct : IGrouping&lt;char, int&gt; {...} 编译

这是 Krzysztof Cwalina 撰写的一篇很好的博客 post,它描述了 Duck 如何在 foreach 中使用输入:

C# 的 foreach 运算符已经使用了鸭子类型。这可能会让一些人感到惊讶,但要在 C# 中支持 foreach,您不需要实现 IEnumerable!您所要做的就是:

提供一个不带参数的公共方法GetEnumerator,它返回一个有两个成员的类型:a) 一个不带参数并返回布尔值的方法MoveMext,b) 一个带有getter 的属性Current返回一个对象。

【讨论】:

  • 不能出现编译时错误的原因是我们使用了接口。编译器知道它有一个IGrouping&lt;char, int&gt;(来自Current 属性类型),但是无论什么类实现它,原则上也可以实现IGrouping&lt;char, string&gt;。任何人都可以编写一个实现这两者的类。由于编译器不能排除产生的实际元素都是这样的,所以它是允许的。我的建议是在所有 foreach 语句中使用 var
  • @JeppeStigNielsen:“原则上也可以实现 IGrouping。” -- 但是如果调用的 GetEnumerator() 方法没有枚举该接口,它没有帮助。接口兼容性是一个完整的红鲱鱼。 “由于编译器不能排除...” -- 但是,再次...只是因为这是foreach 语句的开发人员的特定选择。当引入泛型时,规范可能已更改为要求直接类型兼容性而不是使用鸭子类型(如您的评论所暗示的那样,不强制转换为预期的接口......再次,红鲱鱼)。
  • @JeppeStigNielsen:“我的建议是在所有 foreach 语句中使用 var。” -- 呃,真的吗?这将完全否定通过鸭子类型实现偶数类型兼容性的有用性,因为当集合类型与您所需的循环变量类型不完全匹配时,您必须自己编写显式转换。
  • @JeppeStigNielsen 我不认为这是因为使用了接口。如果是这个原因,那么声明 foreach (MyStruct values in occurrences) 是有效的,因为 MyStruct 也可能实现该接口。但是如果在示例中使用值类型,则会收到编译时错误。
  • 正如我在对现已删除的答案的评论中所说,例如问题中的foreach (string values in occurrences)occurrences,不得编译(stringsealed 并且确实不执行IGrouping&lt;char, int&gt;)。
猜你喜欢
  • 2011-03-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-04
  • 1970-01-01
  • 2021-04-30
  • 1970-01-01
相关资源
最近更新 更多