2012-03-05 26 views
5

che sto cercando di capire perché questo cast non funziona:Perché questo esempio di casting C# non funziona?

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

Questo genera un errore di runtime:

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

Qualcuno può spiegare perché questo non funziona, e se posso andare in giro in qualche modo?

+0

Quale riga genera l'errore? – ChrisF

+0

Quale è corretto dire: A FooList è una lista oppure una lista è FooList? –

+0

@AnthonyPegram Il primo. – hvd

risposta

5

Non è possibile eseguire il cast automatico da una classe genitore a una classe derivata: solo perché l'oggetto che si sta tentando di trasmettere è un List<Foo> non necessariamente lo rende un FooList.

Partenza:

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

Si potrebbe scrivere un operatore che converte un List<Foo> ad un FooList, magari utilizzando AddRange per popolare i valori, come ad esempio:

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

Inoltre, potrebbe essere meglio utilizzare solo un alias using: http://msdn.microsoft.com/en-us/library/sf0df423(v=vs.80).aspx

using FooList = List<Foo>; 

In questo modo non sta effettivamente passando intorno classi inutili derivata.

+1

Forse downcast? – user1096188

+0

Grazie, e usare 'using' è un buon consiglio ... il mio unico problema con esso (e il motivo per cui stavo cercando di usare le classi per aggirarlo) è che l'uso di' non può dipendere da un tipo definito in un altro ' using'. Associandolo al fatto che 'using' ha bisogno di usare un typename pienamente qualificato (vale a dire, è necessario usare' System.Collections.Generic.List' piuttosto che 'List') e le dichiarazioni di' using' diventano veramente veloci. – Eric

7

Proprio perché FooList è una lista non rende l'elenco una lista di oggetti.

4

Questo metodo:

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

... non restituisce un FooList. Il tuo codice è in questo modo:

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

Questo semplicemente non funziona. È invalido come:

string x = (string) new object(); 

Non ti aspetteresti che funzioni, vero? Quindi, perché dovrebbe funzionare la tua versione FooList?

2

Il più vicino C# deve un typedef si chiama direttiva alias utilizzando:

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

Quello che hai crea una classe derivata FooList, ma questo crea un alias FooList. Non è in qualche modo compatibile con List<Foo>, è èList<Foo>.

1

Poiché si sa che uno FooList è in realtà solo un altro nome per uno List<Foo> può sembrare strano. Ma dato che uno FooList potrebbe contenere membri, diventa evidente che il compilatore non dovrebbe consentire il cast. Immagina che in un secondo momento introdurre un metodo (Bar()) sul FooList. Questo metodo non è presente su List<Foo> e il sistema di tipi si interromperebbe semplicemente se l'assegnazione (o il cast) era consentito.

2

Perché non tutti gli elenchi sono FooList. Per esempio, ho potuto avere:

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

Anch'essa eredita da Lista, ma non è lo stesso di un FooList e un FooList non è lo stesso di esso.

1

Non puoi emettere un messaggio; ma potresti creare una nuova istanza di FooList e il suo contenuto

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