在这种情况下,我有一个更多派生类型的列表和另一个派生类型较少的列表.为了避免派生较少的列表中的任意混乱,我写了一个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类型为正,所以不应该首先是转换.有没有办法绕过这个问题?
有没有办法绕过这个问题?
是的 - 你投了它:
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)
根据您的要求,还有其他各种替代方案.
请注意,使用is或as不比较类型名称会更清晰.我还强烈建议您养成为所有foreach语句使用大括号的习惯,即使在语句中只有一个语句的大括号,并遵循局部变量的常见命名约定(listA而不是ListA例如).
还要注意,这不是编译器"不够聪明"的问题 - 这是编译器遵循C#语言规范规则的问题.编译时类型a是A- 就这么简单.碰巧在循环中的任何其他代码都不会更改该编译时类型,因此不会更改您使用它的方式.
虽然偶尔这可能很烦人,但它使语言更加简单和可预测.如果先前的操作改变了重载分辨率的工作方式等,那将是非常奇怪的.