2012-03-05 12 views
5

estoy tratando de entender por qué este reparto no funciona:¿Por qué este ejemplo de fundición de C# no funciona?

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

namespace CastTest { 

    class Foo {} 

    // I want to use this kind of like a typedef, to avoid writing List<Foo> everywhere. 
    class FooList : List<Foo> {} 

    class Program { 
     static void Main(string[] args) { 
      FooList list = (FooList) Program.GetFooList(); 
     } 

     // Suppose this is some library method, and i don't have control over the return type 
     static List<Foo> GetFooList() { 
      return new List<Foo>(); 
     } 
    } 
} 

Esto genera un error de ejecución:

InvalidCastException: Unable to cast object of type 'System.Collections.Generic.List`1[CastTest.Foo]' to type 'CastTest.FooList'.

Puede alguien explicar por qué esto no funciona, y si puedo ¿superar esto de alguna manera?

+0

¿Qué línea genera el error? – ChrisF

+0

¿Qué es correcto decir: un Foolist es una lista , o una lista es un FooList? –

+0

@AnthonyPegram El primero. – hvd

Respuesta

5

No se puede convertir automáticamente de una clase principal a una clase derivada: el hecho de que el objeto que intentas lanzar sea List<Foo> no necesariamente lo convierte en FooList.

Salida:

http://social.msdn.microsoft.com/Forums/is/csharplanguage/thread/f7362ba9-48cd-49eb-9c65-d91355a3daee

Se podría escribir un operador que convierte una List<Foo> a un FooList, tal vez usando AddRange a rellenar los valores, tales como:

class FooList 
{ 
public explicit operator FooList(List<Foo> arg) 
{ 
    FooList result = new FooList(); 
    result.AddRange(arg); 
    return result; 
    } 
} 

Además, puede ser mejor usar un alias using: http://msdn.microsoft.com/en-us/library/sf0df423(v=vs.80).aspx

using FooList = List<Foo>; 

De esta manera no estás pasando clases derivadas innecesarias.

+1

¿Tal vez abatido? – user1096188

+0

Gracias, y usar 'using' es un buen consejo ... mi único problema con eso (y la razón por la que estaba tratando de usar clases para evitarlo) es que un' using' no puede depender de un tipo definido en otro ' usando'. Emparéjalo con el hecho de que 'using' necesita usar un nombre de tipo completamente calificado (es decir, necesitas usar' System.Collections.Generic.List' en lugar de 'List') y las declaraciones' using' se convierten en real wordy real rápidamente. – Eric

7

El hecho de que su Foolist sea una lista no hace que la lista sea una lista de discusión.

4

Este método:

static List<Foo> GetFooList() { 
    return new List<Foo>(); 
} 

... no devuelve un FooList. Su código es efectivamente así:

FooList list = (FooList) new List<Foo>(); 

Eso simplemente no va a funcionar. Es tan inválido como:

string x = (string) new object(); 

No esperaría que eso funcione, ¿verdad? Entonces, ¿por qué funcionaría su versión FooList?

2

Lo más cerca que C# tiene a un typedef se llama una directiva alias usando:

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

namespace CastTest { 
    using FooList = List<Foo>; 

    class Foo {} 

    class Program { 
     static void Main(string[] args) { 
      FooList list = Program.GetFooList(); 
     } 

     // Suppose this is some library method, and i don't have control over the return type 
     static List<Foo> GetFooList() { 
      return new List<Foo>(); 
     } 
    } 
} 

Lo que tienes crea una clase derivada FooList, pero esto crea un alias FooList. No es algo compatible con List<Foo>, es esList<Foo>.

1

Dado que usted sabe que un FooList es en realidad solo otro nombre para un List<Foo> puede parecer extraño. Pero dado que un FooList podría contener miembros por sí mismo, se vuelve aparente que el compilador no debe permitir el reparto. Imagine que más adelante introduce un método (Bar()) en el FooList. Este método no está presente en List<Foo> y el sistema de tipo simplemente se rompería si se permitiera la asignación (o el molde).

2

Porque no todas las listas son FooList. Por ejemplo, podría tener:

public class AnotherFooList : List<Foo> 
{ 
    public object AdditionalPropery {get; set; } 
} 

Es también hereda de la lista, pero no es lo mismo que un FooList y una FooList no es lo mismo que ella.

1

No se puede subir; pero podría crear una nueva instancia de FooList y su contenido

class Foo { } 

    // I want to use this kind of like a typedef, to avoid writing List<Foo> everywhere. 
    class FooList : List<Foo> {} 

    class Program 
    { 
     static void Main(string[] args) 
     { 
      FooList l = new FooList(); 
      l.AddRange(GetFooList().Select(foo => foo)); 

      Console.ReadLine(); 
     } 

     // Suppose this is some library method, and i don't have control over the return type 
     static List<Foo> GetFooList() 
     { 
      return new List<Foo>(); 
     } 
    } 
Cuestiones relacionadas