在这种情况下,我有一个更多派生类型的列表和另一个派生类型较少的列表。为了避免派生较少的列表中的任意混乱,我写了一个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类,因为编译器不够聪明,无法实现转换的实例被测试为类型为正B所以首先不应该进行转换。有没有办法绕过这个问题?
答案 0 :(得分:5)
有没有办法规避这个问题?
是的 - 你投了它:
foreach (A a in listA)
{
if (a.GetType().ToString() == "Test.B")
{
listA.Remove(a);
listB.Add((B) a);
}
}
那将编译,但它仍然会失败,因为你正在修改你正在迭代的集合。 最简单解决此问题的方法是迭代遍历列表的副本:
foreach (A a in listA.ToList())
根据您的要求,还有其他各种替代方案。
请注意,使用is
或as
而不是比较类型名称会更清晰。我还强烈建议你养成为所有foreach
语句使用大括号的习惯,即使在语句中只有一个语句的大括号,并遵循局部变量的通用命名约定({{1}例如,而不是listA
。
另请注意,这不是编译器的问题而且不够聪明&#34; - 这是编译器遵循C#语言规范规则的问题。 ListA
的编译时类型是a
- 它就这么简单。碰巧在循环中的任何其他代码都不会改变编译时类型,因此不会改变您使用它的方式。
虽然偶尔这可能很烦人,但它使语言更加简单和可预测。如果先前的操作改变了重载决策的工作方式等,那么真的很奇怪。