繁体   English   中英

C#多态性简单问题

[英]C# polymorphism simple question

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

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

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

这里有几个问题。

首先:“我可以将Tiger类型的对象分配给Animal类型的变量。为什么我不能将List of 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实例?”

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

这永远不会奏效; 毕竟List<Y> lstY = lstX; 只是复制参考(除非你自己的隐式静态转换操作符添加到您自己的列表类型) -所以它仍然是一个列表X ,并可能含有比其他东西Y实例。

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

但有趣的是,这 (和总是)作参考类型的数组工作,但仅在方向X[] arrX = arrY; 它没有转换任何东西; 如果你尝试将错误的数据放入其中会引发异常。

试试这个:


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
    }
}

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

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

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

您可以尝试从X转换为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);
}

您的方案与通常的多态用例相反。 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...
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM