2010-09-15 15 views
27

¿Por qué esto genera un error de compilación:¿Por qué una expresión de inicializador de colección requiere que se implemente IEnumerable?

class X { public void Add(string str) { Console.WriteLine(str); } } 

static class Program 
{ 
    static void Main() 
    { 
     // error CS1922: Cannot initialize type 'X' with a collection initializer 
     // because it does not implement 'System.Collections.IEnumerable' 
     var x = new X { "string" }; 
    } 
} 

pero esto no lo hace:

class X : IEnumerable 
{ 
    public void Add(string str) { Console.WriteLine(str); } 
    IEnumerator IEnumerable.GetEnumerator() 
    { 
     // Try to blow up horribly! 
     throw new NotImplementedException(); 
    } 
} 

static class Program 
{ 
    static void Main() 
    { 
     // prints “string” and doesn’t throw 
     var x = new X { "string" }; 
    } 
} 

¿Cuál es la razón para restringir inicializadores colección - que son el azúcar sintáctica para una llamada a un método Add - a las clases que implementan una interfaz que no tiene tiene un método Add y que no se utiliza?

+4

Hay algunas cosas en C# que simplemente no entiendo. Este es uno de ellos. Otro es 'foreach'. – leppie

+2

@leppie: ¿Qué no "entiendes" de foreach? –

+1

@Jon Skeet: Creo que Leppie se refiere al hecho de que el compilador simplemente requiere la presencia de un método sin requerir una interfaz específica que es una especie de comportamiento de pato en un lenguaje fuertemente tipado. –

Respuesta

23

Un objeto initializer does not; un colección inicializador hace. Es así que se aplica a clases que realmente representan colecciones, en lugar de solo arbitrarias que tienen un método Add. Tengo que admitir que de vez en cuando he "implementado" IEnumerable explícitamente, solo para permitir inicializadores de recopilación, pero lancé un NotImplementedException desde GetEnumerator().

Tenga en cuenta que al principio del desarrollo de C# 3, los inicializadores de recopilación tuvieron que implementar ICollection<T>, pero se descubrió que era demasiado restrictivo. Mads Torgersen blogged about this change, y la razón detrás de requerir IEnumerable, en 2006.

+0

¿No se aplicaría el mismo argumento a la sintaxis de la consulta LINQ? Sin embargo, no requiere interfaces, e incluso permite que la "variable de iterador" sea un nombre de tipo y "Dónde/Seleccionar" sea un método estático ... – Timwi

+0

@Timwi: más o menos, aunque es menos probable que una consulta la expresión compilará en realidad contra un tipo arbitrario que un inicializador de colección - Sospecho que 'Add' tiene más" otros significados "que los métodos' Where' y 'Select' con tipos de parámetros apropiados. También tenga en cuenta que * no hay * una interfaz adecuada que se podría haber aplicado a las consultas LINQ de comprobación de cordura: piense en Extents reactivos, que no tienen ninguna interfaz común con LINQ to Objects ... –

+6

No pasa un día sin que yo desee .NET 2 fue la primera versión ... El 90% de todos los cruft en .NET parece provenir de la existencia de .NET 1 con sus elementos no genéricos ... –

Cuestiones relacionadas