Подтвердить что ты не робот

Почему я не могу передать List <Customer> в качестве параметра методу, который принимает List <object>?

Следующий код дает мне эту ошибку:

Невозможно преобразовать из 'System.Collections.Generic.List' в 'System.Collections.Generic.List'.

Как я могу указать компилятору, что клиент действительно наследует объект? Или он просто не наследует общие объекты коллекции (отправка List<string> получает ту же ошибку).

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;
        }
    }
}
4b9b3361

Ответ 1

У .NET нет ковариантности и противоречия (пока).

То, что B происходит от A, не означает, что List<B> происходит от List<A>. Это не так. Это два совершенно разных типа.

.NET 4.0 получит ограниченную совместную дисперсию и противоречие.

Ответ 2

Это проблема ковариации, и это не так просто, как кажется на первый взгляд. С# 4 будет иметь некоторую поддержку для этого.

Чтобы получить представление о проблемах, представьте в вашем случае, что этот актер действительно будет работать. Теперь у вас есть List<object>, который, например, также имеет метод Add. Однако аргумент для фактического Add должен быть Customer, так что это явно нарушает реализацию; реализация не предоставляет метод Add(object obj).

К сожалению, некоторые проблемы могут быть решены с помощью интеллектуального (er) дизайна интерфейсов с помощью общих методов, где ковариация в порядке, например, для GetEnumerator.

Ответ 3

С# (в настоящее время) не поддерживает дисперсию для общих типов.

Однако, если вы используете С# 3.0, вы можете сделать это:

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

Ответ 4

Это потому, что список класса не конвертируется в список базового класса. Это преднамеренное решение сделать язык безопасным. Этот вопрос часто задают.

Здесь - мой стандартный ответ о том, как обойти эту проблему:

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

или

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

Также здесь - действительно хорошее объяснение самого Эрика Липперта, одного из главных архитекторов команды С#.

Ответ 5

Это было затронуто ad-nauseum во многих других ответах. Короткий ответ таков:

У меня есть следующие переменные:

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

Теперь, где он прекращает компиляцию:

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

objects.Add("foo"); 

Это имеет смысл сейчас?

С# 4.0 будет вводить ограниченную возможность делать то, что вы пытаетесь сделать, хотя возможность делать то, что вы описываете (назначить List<Customer> на List<object> не будет разрешено по тем же соображениям, которые я изложил выше), См. блог Эрика Липперта для получения дополнительной информации и исправление некоторой дезинформации, которая происходит вокруг межсетевых экранов.

Чтобы ответить на ваш комментарий выше, нет причин, по которым вы не можете выполнять одни и те же операции отражения в экземпляре Customer, как вы можете на object.

Ответ 6

Вместо того, чтобы передавать 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();
        }
    }
}

Ответ 7

Почему параметр не может иметь тип IList?

public void FillSmartGrid (элементы IList)

Ответ 8

Я согласен с ответом Уинстона Смита.

Я просто хотел указать в качестве альтернативы (хотя это, возможно, не лучший способ справиться с ситуацией), что, хотя List<Customer> не получается из List<Object>, Customer [] выводит объект Object [].

Следовательно, это можно сделать:

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

    public void FillSmartGrid(object[] items)
    {
    }

Конечно, недостатком является то, что вы создаете объект массива, чтобы передать его этой функции.