C#多态性简单问题

我有一个类X和一个Y类,后者派生自X:

class x {} class y : x {} 

然后我在某处使用X列表:

 List lstX; ... 

然后我想从我的其他列表中的数据中使用一个新的Y列表……沿着这些方向:

 List lstY = lstX; 

我相信X列表中的项目会自动转换为Y,但事实并非如此。

另外,我如何从某个X初始化Y的新实例? 我想要做 :

 var newX = new X(); var newY = new Y(X); 

但它似乎并没有像那样工作。

谢谢你的帮助! 抱歉格式化,尽我所能

这里有几个问题。

首先:“我可以将Tiger类型的对象分配给Animal类型的变量。为什么我不能将List of Tiger类型的对象分配给List of Animal类型的变量?”

因为这会发生:

 List tigers = new List(); List animals = tigers; // this is illegal because if we allow it... animals.Add(new Giraffe()); // ... then you just put a giraffe into a list of tigers. 

在C#4中,这样做是合法的:

 IEnumerable tigers = new List(); IEnumerable animals = tigers; 

这是合法的,因为IEnumerable没有“添加”方法,因此保证这是安全的。

有关协方差的一系列文章,请参阅有关C#4这一新function的详细信息。

http://blogs.msdn.com/ericlippert/archive/tags/Covariance+and+Contravariance/default.aspx

第二个问题:“我怎么能从某个动物身上初始化一个新的Tiger实例?”

你不能。 有问题的动物可能是瓢虫。 你如何从瓢虫的实例初始化一只新老虎? 这没有任何意义,所以我们不允许你这样做。 如果你想编写自己的特殊方法,知道如何将任意动物变成老虎,你可以自由地这样做。 但我们不知道如何为你做到这一点。

这永远不会起作用; 毕竟List lstY = lstX; 只需复制引用(除非您将自己的隐式静态转换运算符添加到您自己的列表类型中) – 因此它仍然X的列表,并且可以包含除Y实例之外的其他内容

即使在4.0中,co / contra方差也不会扩展到:列表( inout ),或b:具体类型(如List )。

有趣的是,它将(并且始终)适用于引用类型的数组,但仅在方向X[] arrX = arrY; 。 它没有转换任何东西; 如果您尝试将错误的数据放入其中,则会抛出exception。

不,因为您不能确定listX中所有类型为“X”的项目也是Y类型。
inheritance关系是另一种方式:Y类型的项可以转换为X,因为Y -X。

在C#中,也没有像C ++那样可用的“复制构造函数”,所以我担心你必须实现那个逻辑,以便能够从某个X初始化一个新的Y实例,你自己。 另外,请记住,类是引用类型…

它不能自动“扩展”对象的类型从x到y,因为X不是Y,而Y X.

您可以尝试从X转换为Y,但是这将失败并出现InvalidCastException除非您的对象最初是Y伪装为X。 您需要手动初始化并填充新的List

 IList yList = new List(); foreach (var x in xList) { var y = new Y(x); // Copies/clones inherited properties from x to a new Y // TODO: Set other properties of y not present on x yList.Add(y); } 

试试这个:

 using System.Collections.Generic; namespace ConsoleApplication1 { class Program { static void Main(string[] args) { List myList; myList = GetMyList(MyListTypeEnum.MyList1); myList = GetMyList(MyListTypeEnum.MyList2); } public static List GetMyList(MyListTypeEnum tipo) { List result; result = new List(); switch (tipo) { case MyListTypeEnum.MyList1: List myList1 = GetMyList1(); foreach (var item in myList1) { result.Add((IMyList) item); } break; case MyListTypeEnum.MyList2: List myList2 = GetMyList2(); foreach (var item in myList2) { result.Add((IMyList) item); } break; } return result; } public static List GetMyList1() { List myList1 = new List(); myList1.Add(new MyList1 { Code = 1 }); myList1.Add(new MyList1 { Code = 2 }); myList1.Add(new MyList1 { Code = 3 }); return myList1; } public static List GetMyList2() { List myList2 = new List(); myList2.Add(new MyList2 { Name = "1" }); myList2.Add(new MyList2 { Name = "2" }); myList2.Add(new MyList2 { Name = "3" }); return myList2; } } public interface IMyList { } public class MyList1 : IMyList { public int Code { get; set; } } public class MyList2 : IMyList { public string Name { get; set; } } public enum MyListTypeEnum { MyList1, MyList2 } } 

您的方案与通常的多态用例相反。 Y是X,但X不是Y.

考虑到这一点,您可以通过将克隆代码放置在构造函数和诸如此类的东西中来强制它以您所说的方式工作。

你的第一个例子的问题是Y派生自X,所以它“是一个X”,但“X不是Y”,C#目前也不支持这种方法中的类型转换。 您可以尝试使用Cast的扩展方法,例如lstX.ConvertAll作为帮助程序来完成此操作。

对于第二个问题,您要查看Copy构造函数,例如:

 public Y(X baseObject) { //copy all the data you need here... }