我得到了一个X类和一个Y类,后者来自X:
class x {}
class y : x {}
然后在某处我使用X列表:
List<X> lstX;
...
然后我想从我的其他列表中的数据中使用一个新的Y列表...这些内容:
List<Y> lstY = lstX;
我相信X列表中的项目会自动转换为Y,但事实并非如此。
另外,如何从某个X初始化Y的新实例?我想这样做:
var newX = new X();
var newY = new Y(X);
但似乎并没有像那样工作。
感谢您的帮助! 抱歉格式化,尽我所能
答案 0 :(得分:27)
这里有几个问题。
首先:“我可以将Tiger类型的对象分配给Animal类型的变量。为什么我不能将Tiger类型的对象分配给List of Animal类型的变量?”
因为这会发生:
List<Tiger> tigers = new List<Tiger>();
List<Animal> 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<Tiger> tigers = new List<Tiger>();
IEnumerable<Animal> animals = tigers;
这是合法的,因为IEnumerable<T>
没有“添加”方法,因此保证这是安全的。
请参阅我关于协方差的系列文章,了解有关C#4这一新功能的详细信息。
http://blogs.msdn.com/ericlippert/archive/tags/Covariance+and+Contravariance/default.aspx
第二个问题:“我怎样才能从某个动物身上初始化一个新的Tiger实例?”
你做不到。有问题的动物可能是瓢虫。你是如何从瓢虫的实例初始化一只新老虎的?这没有任何意义,所以我们不允许你这样做。如果你想编写自己的特殊方法,知道如何将任意动物变成老虎,你可以自由地这样做。但我们不知道如何为你做到这一点。
答案 1 :(得分:3)
这永远不会奏效;毕竟List<Y> lstY = lstX;
只复制引用(除非你将自己的隐式静态转换运算符添加到你自己的列表类型中) - 所以仍然是一个X
的列表,并且可以包含事情其他而不是Y
个实例。
即使在4.0中,co / contra方差也不会扩展到:列表(in
和out
),或b:具体类型(如List<T>
)。
有趣的是,将(并且始终有)适用于引用类型数组,但仅限于X[] arrX = arrY;
方向。它没有转换任何东西;如果您尝试将错误的数据放入其中,则会抛出异常。
答案 2 :(得分:1)
不,因为您无法确定listX中属于“X”类型的所有项目的类型是否为Y.
继承关系是另一种方式:Y类型的项目可以转换为X,因为Y 是-a X.
在C#中,也没有像C ++那样可用的“复制构造函数”,所以我担心你必须实现那个逻辑,以便能够从某个X初始化一个新的Y实例,你自己。 另外,请记住,类是引用类型......
答案 3 :(得分:1)
它不能自动“扩大”对象的类型从x到y,因为X不是Y,而Y 是 X.
您可以尝试从X转换为Y,但是除非您的对象原本是Y伪装为X,否则它将失败InvalidCastException
。您需要手动初始化并填充新的List<Y>
:
IList<Y> yList = new List<Y>();
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);
}
答案 4 :(得分:1)
试试这个:
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
}
}
答案 5 :(得分:0)
您的方案与通常的多态用例相反。 Y是X,但X不是Y.
考虑到这一点,你可以强制它按照你说的方式工作,将克隆代码放在构造函数中等等。
答案 6 :(得分:0)
你的第一个例子的问题是Y派生自X,所以它是“X”,但“X不是Y”,C#目前也不支持此方法中的类型转换。您可以尝试使用Cast的扩展方法,例如lstX.ConvertAll作为帮助程序来完成此操作。
对于第二个问题,您要查看Copy构造函数,例如:
public Y(X baseObject) {
//copy all the data you need here...
}