虽然可以从基类/接口继承,但为什么不能声明List<>呢
使用相同的类/接口?
interface A
{ }
class B : A
{ }
class C : B
{ }
class Test
{
static void Main(string[] args)
{
A a = new C(); // OK
List<A> listOfA = new List<C>(); // compiler Error
}
}
有别的办法吗?
我已经阅读了整篇文章,我只是想指出对我来说似乎不一致的地方。
编译器阻止你对list执行赋值操作:
List<Tiger> myTigersList = new List<Tiger>() { new Tiger(), new Tiger(), new Tiger() };
List<Animal> myAnimalsList = myTigersList; // Compiler error
但是编译器完全可以处理数组:
Tiger[] myTigersArray = new Tiger[3] { new Tiger(), new Tiger(), new Tiger() };
Animal[] myAnimalsArray = myTigersArray; // No problem
关于任务是否安全的争论在这里站不住脚了。我对数组的赋值是不安全的。为了证明这一点,如果我继续这样做:
myAnimalsArray[1] = new Giraffe();
我得到一个运行时异常“ArrayTypeMismatchException”。如何解释这一点呢?如果编译器真的想阻止我做一些愚蠢的事情,它应该阻止我做数组赋值。
至于为什么它不起作用,理解协方差和逆变可能会有所帮助。
只是为了说明为什么这不能工作,这里是对您提供的代码的更改:
void DoesThisWork()
{
List<C> DerivedList = new List<C>();
List<A> BaseList = DerivedList;
BaseList.Add(new B());
C FirstItem = DerivedList.First();
}
这可行吗?列表中的第一个项是类型“B”,但派生列表项的类型是C。
现在,假设我们真的只想创建一个泛型函数,它对实现了a的某个类型的列表进行操作,但我们不关心它是什么类型:
void ThisWorks<T>(List<T> GenericList) where T:A
{
}
void Test()
{
ThisWorks(new List<B>());
ThisWorks(new List<C>());
}
这是对BigJim的精彩回答的延伸。
在我的例子中,我有一个带有子字典的NodeBase类,我需要一种方法来从子字典中进行O(1)查询。我试图在Children的getter中返回一个私有字典字段,所以显然我想避免昂贵的复制/迭代。因此,我使用Bigjim的代码将Dictionary<whatever特定类型>转换为generic Dictionary<NodeBase>:
// Abstract parent class
public abstract class NodeBase
{
public abstract IDictionary<string, NodeBase> Children { get; }
...
}
// Implementing child class
public class RealNode : NodeBase
{
private Dictionary<string, RealNode> containedNodes;
public override IDictionary<string, NodeBase> Children
{
// Using a modification of Bigjim's code to cast the Dictionary:
return new IDictionary<string, NodeBase>().CastDictionary<string, RealNode, NodeBase>();
}
...
}
这很有效。然而,我最终遇到了不相关的限制,并最终在基类中创建了一个抽象的FindChild()方法来代替它进行查找。事实证明,这从一开始就消除了对强制转换字典的需求。(出于我的目的,我可以用一个简单的IEnumerable替换它。)
所以你可能会问的问题(特别是当性能问题禁止你使用.Cast<>或.ConvertAll<>)是:
“我真的需要强制转换整个集合吗?或者我可以使用抽象方法来保存执行任务所需的特殊知识,从而避免直接访问集合吗?”
有时候最简单的解决方案就是最好的。