Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/293.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# Foreach可以抛出一个InvalidCastException?_C#_Foreach_Language Design - Fatal编程技术网

C# Foreach可以抛出一个InvalidCastException?

C# Foreach可以抛出一个InvalidCastException?,c#,foreach,language-design,C#,Foreach,Language Design,想象一下下面的代码: class foreach_convert { public static void method2() { List<IComparable> x = new List<IComparable>(); x.Add(5); foreach (string s in x) { //InvalidCastException in runtime

想象一下下面的代码:

class foreach_convert
{
    public static void method2()
    {
        List<IComparable> x = new List<IComparable>();
        x.Add(5);

        foreach (string s in x)
        {
            //InvalidCastException in runtime
        }
    }
}
类foreach\u转换
{
公共静态无效方法2()
{
列表x=新列表();
x、 增加(5);
foreach(x中的字符串s)
{
//运行时中的InvalidCastException
}
}
}
我想知道,为什么每个人的行为如此。。。不是C#-像什么? 这里发生的是对一个子类的隐式转换,该子类容易出错,并且在语言的其他地方似乎都被禁止。还是我不对


另外,我问这个问题的原因是,我的项目中类似的代码中有一个bug,我曾经迭代过一个来自外部库的自定义集合,它被称为像
SomeTypeCollection
,但实际上提供了一个基类型项的集合,并且可能包含
SomeOtherType
的项。我的错,但是语言和编译器都没有提供任何明确的提示/警告,这对于C#来说是很不寻常的

对于C#3,我使用的是var,因此我得到了编译器警告。

foreach在IEnumerable上工作,它返回类型为object的对象。对于每个项目,对象都将强制转换为您提供的类型


除非在C#3.0中使用var。如果该类型是由集合实现的,则该类型将取自
IEnumerable

回想一下泛型之前的情况
foreach
必须进行强制转换,以便您可以执行以下明智的操作:

foreach (string x in names)
{
    // ...
}
而不是:

foreach (object tmp in names)
{
    string x = (string) tmp;
    // ...
}
在我看来,后者很讨厌。提供隐式转换与语言的其他部分不同,但在绝大多数情况下,它更易于使用

我怀疑,如果C#从泛型和扩展方法开始(因此我们可以使用and),那么
foreach
就不会以完全相同的方式指定


请注意,
foreach
中还有更奇怪的地方:该类型根本不必实现
IEnumerable
。只要它有一个
GetEnumerator
方法,该方法返回的东西依次有
MoveNext()
Current
,C编译器就很高兴。这意味着您可以在泛型之前实现一个“强类型迭代器”(以避免装箱)。

这给人的印象是foreach(列表中的int x)将装箱,然后取消装箱,而事实并非如此。C#编译器在可用的情况下优先使用IEnumerable而不是IEnumerable。关于类型化接口,您是对的。有时候C#规范有点不一致:foreach构造似乎是C#中唯一允许协方差和逆变的东西。对。我怀疑这是从第一个C#开始的传统,现在将其强类型化是一个突破性的改变。。。[抱怨]尽管如此,MSDN中可能有一个警告或只是一个注释:-)好了,现在更新更多,并且能够理解。。。好。。。话。。。不要认为我的答案添加了任何这里没有提到的内容:)他们可以在没有泛型的情况下构建相关功能,而不是实现这种荒谬的隐式转换。这一点很好。在foreach中使用var可以避免该错误,因为它会检测到您正在迭代的集合的确切类型。嘿,我第一次遇到这个问题时,我希望(不是真的期望)foreach会根据对象的类型隐式过滤集合中的对象。想想它是怎么读的,“对于集合中的每个字符串。”对我来说,这就像是“对于集合中的所有字符串,做点什么。”然后它会忽略任何非字符串的内容。