简体   繁体   English

设计模式:对象列表的多态性

[英]Design pattern: Polymorphism for list of objects

Suppose I have a class A, and A1, A2 inherits from A. There are 2 functions: 假设我有一个A类,A1,A2继承自A。有2个函数:

List<A1> getListA1(){...}
List<A2> getListA2(){...}

Now I want to do something similar to both A1 and A2 in another function 现在我想在另一个函数中执行类似于A1和A2的操作

public void process(List<A>){...}

If I want to pass the instance of either ListA1 or ListA2, of course the types doesn't match because the compiler doesn't allow the coercion from List< A1> to List< A>. 如果我想传递ListA1或ListA2的实例,当然类型不匹配,因为编译器不允许从List <A1>到List <A>的强制。 I can't do something like this: 我做不到这样的事情:

List<A1> listA1 = getListA1();
List<A> newList = (List<A>)listA1; //this is not allowed.

So what is the best approach to the process()? 那么这个过程的最佳方法是什么()? Is there any way to do it in a universal way rather than write the similar code to both List and List? 有没有办法以通用的方式做到这一点,而不是将类似的代码写入List和List?

While I can't offer a java solution, here are some for C# ... 虽然我不能提供java解决方案,但这里有一些用于C#...

If you can alter the signature of Process to accept IEnumerable ... 如果你可以改变Process的签名来接受IEnumerable ......

public void Process(IEnumerable<A> myList) { ... }

then, in C# 4.0, everything will just work, thanks to the improved support for co- and contra-variance. 然后,在C#4.0中,由于对共同和反差的改进支持,一切都将正常工作。

If you're working in C# 3.0, you can introduce a generic type parameter to the method: 如果您使用的是C#3.0,则可以在方法中引入泛型类型参数:

public void Process<T>(List<T> myList) where T : A { ... }

Then, you can call passing either List or List and the generic type parameter will bind accordingly. 然后,您可以调用传递List或List,并且泛型类型参数将相应地绑定。 Note that you don't often have to specify it directly, as type inferrence will usually give you what you need. 请注意,您通常不必直接指定它,因为类型推断通常会为您提供所需的内容。

If this doesn't suit, you could convert the List using the Cast extension method from Enumerable: 如果这不合适,您可以使用Enumerable中的Cast扩展方法转换List:

public void Process(List<A> myList) { ... }

var someList = getListA1();
Process( someList.Cast<A>());

使用通配符绑定:

public void process(List<? extends A>){...}
import java.util.*;

class A {
    int x;
}

class A1 extends A {
    int y;
}

class A2 extends A {
    int z;
}

public class polymorphisimForListOfObjects {
    static void foo(List<? extends A> l) { // probably can't modify the list
        System.out.println(l);
    }

    public static void main(String[] arguments) {
        A1[] a1 = { new A1(), new A1() };
        A2[] a2 = { new A2(), new A2() };
        List<A1> l1 = Arrays.asList(a1);
        List<A2> l2 = Arrays.asList(a2);
        foo(l1);
        foo(l2);
    }

}

Try this example: 试试这个例子:



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

使用IEnumerable中的Cast扩展方法。

Can't getListA1() and getListA2() just return List types in the first instance? getListA1()getListA2()只能在第一个实例中返回List类型吗?

List<A> getListA1(){...}
List<A> getListA2(){...}

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

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