2009-12-02 7 views
12

El siguiente código me da este error:¿Por qué no puedo pasar la lista <Customer> como parámetro a un método que acepta la lista <object>?

Cannot convert from 'System.Collections.Generic.List' to 'System.Collections.Generic.List'.

¿Cómo puedo indicar al compilador que el Cliente de hecho hereda de objeto? ¿O simplemente no hereda con objetos de colección genéricos (enviar un List<string> obtiene el mismo error).

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; 
     } 
    } 
} 
+2

¿Por qué está tomando en la lista artículos? – JonH

+0

para hacer una reflexión sobre ellos y procesarlos dinámicamente –

+0

Aún puede realizar la reflexión sobre un objeto 'Cliente' de la misma manera que lo puede hacer con un' objeto'. –

Respuesta

14

.NET no tiene co-varianza y contra-varianza (todavía).

Que B se deriva de A no implica que List<B> deriva de List<A>. No es así Son dos tipos totalmente diferentes.

.NET 4.0 obtendrá co-varianza y contra-varianza limitadas.

+1

No creo que la covarianza en .NET 4 ayude en esta situación. –

+0

@Mark Byers: ¿por qué? parece que debería ayudar mucho – Randolpho

+3

@Mark es correcto. El soporte de covarianza que se agrega a C# está limitado a interfaces y delegados. La lista es un tipo concreto y no puede aprovecharse aquí – JaredPar

7

C# (en la actualidad) no es compatible con la varianza para los tipos genéricos.

Sin embargo, si usted está usando C# 3.0, usted puede hacer esto:

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

+1 para esto. Si es anterior a la versión 3, puede escribir un método para convertir la lista en una lista . – Fenton

8

Ese es el problema de la covarianza, y no es tan fácil como parece a primera vista. C# 4 tendrá algo de apoyo para eso.

Para hacerse una idea de los problemas, imagine en su caso que este elenco realmente funcionaría. Ahora tiene un List<object>, que por ejemplo también tiene un método Add. Sin embargo, el argumento para el Add real debe ser un Customer, por lo que esto claramente infringe la implementación; la implementación no proporciona el método Add(object obj).

Desafortunadamente, algunos problemas podrían haberse resuelto utilizando un diseño inteligente (er) de las interfaces con métodos genéricos donde la covarianza es correcta, como para GetEnumerator.

6

Es porque una lista de una clase no es convertible a una lista de la clase base. Es una decisión deliberada para hacer que el idioma sea seguro. Esta pregunta se hace a menudo.

Here es mi respuesta estándar de cómo evitar el problema:

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

o:

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

también here es muy buena explicación del propio Eric Lippert, uno de los principales arquitectos de el equipo de C#.

2

Esto se ha cubierto ad-nauseum en muchas otras respuestas. La respuesta corta es la siguiente:

Considere tengo estas variables:

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

Ahora, aquí es donde se detiene la compilación:

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

objects.Add("foo"); 

¿Eso tiene sentido ahora?

C# 4.0 introducirá una capacidad limitada para hacer lo que usted está tratando, a pesar de ser capaz de hacer exactamente como usted la describe (asignar un List<Customer> a un List<object> no será permitido para el mismo razonamiento que he descrito). Consulte Eric Lippert's blog para obtener más información y una corrección a la información errónea que circula por las redes internas.

Para abordar su comentario anterior, no hay motivo por el que no pueda realizar las mismas operaciones de reflejo en una instancia de Customer que en un object.

1

En lugar de pasar lista que no funciona por las razones anteriores, es posible que no acaba de pasar simplemente una referencia de objeto a continuación, obtener el tipo de lista después, un poco como ...

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(); 
     } 
    } 
} 
0

Por qué no puede el parámetro ser del tipo IList?

(artículos IList) FillSmartGrid public void

0

Estoy de acuerdo con la respuesta de Winston Smith.

Solo quería señalar como alternativa (aunque posiblemente esta no sea la mejor manera de manejar la situación) que mientras List<Customer> no se deriva de List<Object>, el Cliente [] deriva de Object [].

Por lo tanto, es posible hacer esto:

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

    public void FillSmartGrid(object[] items) 
    { 
    } 

Por supuesto, el inconveniente es que está creando un objeto de matriz sólo para que pueda pasar a esta función.

Cuestiones relacionadas