C#多态性简单问题

时间:2010-02-09 19:01:44

标签: c# polymorphism

我得到了一个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);

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

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

7 个答案:

答案 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方差也不会扩展到:列表(inout),或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...
}