将隐含的派生类型的对象放入更多派生类型的列表中

Max*_*eth 2 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
    }
}
Run Code Online (Sandbox Code Playgroud)

这给了我一个编译器错误,说A类型的对象不能隐式转换为类型B,因为编译器不够聪明,无法实现转换的实例被测试为B类型为正,所以不应该首先是转换.有没有办法绕过这个问题?

Jon*_*eet 5

有没有办法绕过这个问题?

是的 - 你投了它:

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

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

foreach (A a in listA.ToList())
Run Code Online (Sandbox Code Playgroud)

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

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

还要注意,这不是编译器"不够聪明"的问题 - 这是编译器遵循C#语言规范规则的问题.编译时类型aA- 就这么简单.碰巧在循环中的任何其他代码都不会更改该编译时类型,因此不会更改您使用它的方式.

虽然偶尔这可能很烦人,但它使语言更加简单和可预测.如果先前的操作改变了重载分辨率的工作方式等,那将是非常奇怪的.