代码之家  ›  专栏  ›  技术社区  ›  djdd87

为什么我可以在foreach中使用(几乎)任何类型而不是不相关的接口列表?

  •  3
  • djdd87  · 技术社区  · 6 年前

    有了第一个 foreach 在下面的例子中,我确信它应该抛出一个编译错误,但是它们构建得很好。只有在运行时引发无效的强制转换异常时才会出现问题(如您所料):

    public interface IState
    {
        int Id { get; }
        string Description { get; }
    }
    
    public class Dog
    {
        public string Name { get; set; }
        public string Breed { get; set; }
    }
    
    public class Cat
    {
        public string Name { get; set; }
        public string Breed { get; set; }
    }
    
    public void Foo()
    {
        IEnumerable<IState> states = new List<IState>();
        foreach (Dog dog in states) { } // Does not break in the compiler
    
        IEnumerable<Cat> cats = new List<Cat>();
        foreach (Dog dog in cats) { } // Obviously breaks in compiler
    }
    

    为什么编译器会传递这个? Dog IState ,如果我试图遍历 Cat 相反,编译器显然会捕获它。

    1 回复  |  直到 6 年前
        1
  •  3
  •   Jon Skeet    6 年前

    编译器正在隐式地将转换从元素类型转换为您在 foreach 陈述。

    所以如果你有 IEnumerable<Foo> 你把它当作:

    foreach (Bar bar in foos)
    

    然后将插入一个 Foo Bar 是的。如果且仅当该强制转换通常有效时,才会编译此函数。

    不是 可从中强制转换 Cat Dog 因为他们是不相关的类型。一个 参考罐 从未 作为 犬只论坛 参考资料。

    如果 可从中强制转换 IState 犬只论坛 因为它 能够 有效期:

    public class DogState : Dog, IState
    {
        public int Id => 5;
        public string Description => "Dog state!";
    }
    
    IState state = new DogState();
    Dog dog = (Dog) state; // Won't throw
    

    在您的收藏示例中:

    IEnumerable<IState> states = new List<IState> { new DogState() };
    foreach (Dog dog in states)
    {
        Console.WriteLine("I've got a dog state!");
    }