c# - 将隐含为派生程度较低的类型的对象放入派生程度较高的类型的列表中

标签 c# inheritance

在这种情况下,我有一个派生程度较高的类型的列表和另一个派生程度较低的类型的列表。为了避免派生较少的列表中出现任意困惑,我编写了一个 foreach 语句,该语句检查列表中的每个元素是否属于派生较多的类型,如果是,则将其移动到派生较多的列表的该元素。此处演示了这一点:

namespace Test
{
    class Tester
    {
        static void Method()
        {
            List<A> ListA = new List<A>();
            List<B> ListB = new List<B>();
            //populate the lists
            foreach (A a in ListA)
                if (a.GetType().ToString()=="Test.B")
                {
                    ListA.Remove(a);
                    ListB.Add(a);
                }
            //Do stuff with the lists
        }
    }
    class A
    {
        //stuff in class A
    }
    class B : A
    {
        //stuff in class B
    }
}

这给了我一个编译器错误,指出 A 类型的对象不能隐式转换为 B 类型,因为编译器不够聪明,无法意识到要转换的 a 实例是否为 B 类型,因此测试结果为阳性首先不应该进行转换。有没有办法避免这个问题?

最佳答案

Is there a way to circumvent this issue?

是的 - 你施放它:

foreach (A a in listA)
{
    if (a.GetType().ToString() == "Test.B")
    {
        listA.Remove(a);
        listB.Add((B) a);
    }
}

这会编译,但仍然会失败,因为您正在修改正在迭代的集合。解决此问题的最简单方法是迭代列表的副本:

foreach (A a in listA.ToList())

根据您的要求,还有各种其他替代方案。

请注意,使用 isas 比比较类型名称更清晰。我还强烈建议您养成在所有 foreach 语句中使用大括号的习惯,即使是在正文中只有一条语句的语句,并遵循局部变量的常见命名约定 (例如,listA 而不是 ListA)。

另请注意,这不是编译器“不够智能”的问题 - 这是编译器遵循 C# 语言规范规则的问题。 a 的编译时类型是 A - 就这么简单。循环中碰巧出现的任何其他代码都不会更改该编译时类型,因此不会更改您使用它的方式。

虽然有时这可能很烦人,但它使语言变得更加简单且更可预测。如果以前的操作改变了重载解析的工作方式等,那将会真的很奇怪。

关于c# - 将隐含为派生程度较低的类型的对象放入派生程度较高的类型的列表中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27265914/

相关文章:

c# - 有选择地将要绑定(bind)的模型字段列入白名单

c# - 为什么 C# 不支持通过引用传递的运算符重载?

c# 编译器错误 'Parameter must be input safe. Invalid variance. The type parameter ' T' must be invariantly valid on Expression<TDelegate> '

c++ - 从内部类继承

c++ - 初始化 POD 结构的基类

c# - 计算多个日期/时间范围之间的交叉点的位置和数量?

c# - 如何从 Word 编辑器对象(在 Outlook 2010 中)获取所选文本并将其复制到另一个表单?

c++ - 虚函数和双重继承

java - 如何使用具有多列/复合主键(JPA 1.0 @IdClass)的表实现继承?

c++ - 是什么导致了模板和继承中出现这种令人困惑的编译器错误?