为什么我不能将List <customer>作为参数传递给接受List <object>的方法?</object> </customer>

时间:2009-12-02 16:47:23

标签: c# generics

以下代码给出了这个错误:

  

无法转换   'System.Collections.Generic.List'   至   'System.Collections.Generic.List'。

如何向编译器指出Customer确实从对象继承?或者它是否仅使用泛型集合对象进行继承(发送List<string>会得到相同的错误)。< / p>

using System.Collections.Generic;
using System.Windows;
using System.Windows.Documents;

namespace TestControl3423
{
    public partial class Window2 : Window
    {
        public Window2()
        {
            InitializeComponent();

            List<Customer> customers = Customer.GetCustomers();
            FillSmartGrid(customers);

            //List<CorporateCustomer> corporateCustomers = CorporateCustomer.GetCorporateCustomers();
            //FillSmartGrid(corporateCustomers);
        }


        public void FillSmartGrid(List<object> items)
        {
            //do reflection on items and display dynamically
        }
    }

    public class Customer
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string Street { get; set; }
        public string Location { get; set; }
        public string ZipCode { get; set; }

        public static List<Customer> GetCustomers()
        {
            List<Customer> customers = new List<Customer>();
            customers.Add(new Customer { FirstName = "Jim", LastName = "Jones", ZipCode = "23434" });
            customers.Add(new Customer { FirstName = "Joe", LastName = "Adams", ZipCode = "12312" });
            customers.Add(new Customer { FirstName = "Jake", LastName = "Johnson", ZipCode = "23111" });
            customers.Add(new Customer { FirstName = "Angie", LastName = "Reckar", ZipCode = "54343" });
            customers.Add(new Customer { FirstName = "Jean", LastName = "Anderson", ZipCode = "16623" });
            return customers;
        }
    }
}

8 个答案:

答案 0 :(得分:14)

.NET没有协方差和反差(尚未)。

B来自A并不意味着List<B>来自List<A>。它没有。它们是两种完全不同的类型。

.NET 4.0将获得有限的协方差和反差异。

答案 1 :(得分:8)

这就是协方差的问题,并不像第一眼看上去那么容易。 C#4会对此有所支持。

为了了解问题,想象一下你的情况下这个演员实际上是有效的。现在你有一个List<object>,例如它也有一个Add方法。但是,实际Add的参数必须是Customer,因此这显然违反了实施;该实现不提供Add(object obj)方法。

不幸的是,一些问题可以通过使用通用方法的接口的智能(呃)设计来解决,其中协方差是可以的,例如对于GetEnumerator。

答案 2 :(得分:7)

C#(目前)不支持泛型类型的差异。

但是,如果您使用的是C#3.0,则可以执行此操作:

FillSmartGrid( customers.Cast<object>() );

答案 3 :(得分:6)

这是因为类的列表不能转换为基类列表。这是一个刻意决定使语言安全。这个问题经常被问到。

Here是我如何解决这个问题的标准答案:

List<A> listOfA = new List<C>().ConvertAll(x => (A)x);

或:

List<A> listOfA = new List<C>().Cast<A>().ToList();

同样here是Eric Lippert本人的一个很好的解释,他是C#团队的首席架构师之一。

答案 4 :(得分:2)

在许多其他答案中,这已经被令人厌恶。简短的回答是:

考虑我有这些变量:

List<Customer> customers = new List<Customer>(); //ok, seems fair
List<object> objects = new List<object>(); // again, everything's fine

现在,这是停止编译的地方:

objects = customers; // sounds OK, since a Customer is an object, right?

objects.Add("foo"); 

这现在有意义吗?

C#4.0会引入有限的能力来执行您正在尝试的内容,但能够按照您的描述完全(将List<Customer>分配给List<object>赢得'允许我在上面概述的相同推理。有关详细信息,请参阅Eric Lippert's blog,以及对互联网周围的一些错误信息进行更正。

要解决上述评论,您无法在Customer实例上执行与object上相同的反思操作。

答案 5 :(得分:1)

不是传递由于上述原因而无效的List,你不能简单地传递一个对象引用然后获取列表类型,有点像...

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1 {

    class Customer {
        public int id;
        public string name;
    }

    class Monkey {

        public void AcceptsObject(object list) {

            if (list is List<Customer>) {
                List<Customer> customerlist = list as List<Customer>;
                foreach (Customer c in customerlist) {
                    Console.WriteLine(c.name);
                }
            }
        }
    }

    class Program {
        static void Main(string[] args) {

            Monkey monkey = new Monkey();
            List<Customer> customers = new List<Customer> { new Customer() { id = 1, name = "Fred" } };
            monkey.AcceptsObject(customers);
            Console.ReadLine();
        }
    }
}

答案 6 :(得分:0)

为什么参数不能是IList类型?

public void FillSmartGrid(IList项目)

答案 7 :(得分:0)

我同意温斯顿史密斯的回答。

我只是想指出作为替代方案(尽管这可能不是处理这种情况的最佳方式),虽然List<Customer>不是来自List<Object>,但客户[]确实来自对象[]。

因此,可以这样做:

    {
        List<Customer> customers = new List<Customer>();
        // ...
        FillSmartGrid(customers.ToArray());
        // ...
    }

    public void FillSmartGrid(object[] items)
    {
    }

当然,缺点是你正在创建一个数组对象,所以你可以把它传递给这个函数。