2010-01-05 14 views

risposta

76

Sì:

if (typeof(T) == typeof(MyClass)) 
{ 
    MyClass mc = (MyClass)(object) t; 
} 
else if (typeof(T) == typeof(List<MyClass>)) 
{ 
    List<MyClass> lmc = (List<MyClass>)(object) t; 
} 

E' un po 'strano che avete bisogno di andare via un cast da obiettare, ma questo è solo il modo in cui funzionano i generici - non ci sono tante conversioni da un tipo generico come ci si potrebbe aspettare.

Naturalmente un'altra alternativa è quella di utilizzare il normale controllo tempo di esecuzione:

MyClass mc = t as MyClass; 
if (mc != null) 
{ 
    // ... 
} 
else 
{ 
    List<MyClass> lmc = t as List<MyClass>; 
    if (lmc != null) 
    { 
     // ... 
    } 
} 

Che si comportano in modo diverso per il primo blocco di codice se t è nullo, naturalmente.

avrei provo per evitare questo tipo di codice ove possibile, tuttavia - può essere necessario a volte, ma l'idea di metodi generici è essere in grado di scrivere codice generico che funziona allo stesso modo per qualsiasi tipo .

+0

In realtà ho un problema un po 'più complicato. Cosa succede se MyClass deriva da MyBaseClass e ci sono molte altre MyClasses che derivano da MyBaseClass? – synergetic

+1

@synergetic: hai descritto la gerarchia di tipi, ma non quello che vuoi fare con esso. Puoi usare reflection (ad es. 'Typeof (T) .BaseType' o' typeof (T) .IsAssignableFrom (...) 'per esplorare la gerarchia dei tipi, se è utile, proverei comunque ad evitarlo, se possibile :) –

+0

L'odio per essere un asciugamano bagnato qui, ma questa risposta non è sufficiente nei casi in cui T è in realtà un tipo in scatola (es: oggetto boxedMyClass = new MyClass()). In casi come questo, il tipo restituito dall'operatore typeof sarà object, non MyClass, causando il fallimento del controllo typeof di cui sopra. Secondo me, è qui che C# cade brevemente come lingua: occupandosi sia del controllo generico del tipo che della complessa logica ontologica (es. Non c'è modo di dire qualcosa come "aLifeform è Mammal e non Bear" in C# senza entrare nella riflessione). – rmiesen

2

Credo che ci sia qualcosa di sbagliato nella progettazione. Si desidera confrontare i tipi in un metodo già generico. I generici sono pensati per affrontare situazioni di variabile di tipo. vi consiglio di farlo in questo modo ..

//Generic Overload 1 
public void DoSomething<T>(T t) 
    where T : MyClass 
{ 
    ... 
} 

//Generic Overload 2 
public void DoSomething<T>(T t) 
    where T : List<MyClass> 
{ 
    ... 
} 
+0

Se è per questo, è sufficiente rilasciare i generici e specificare il tipo di parametro. Ma +1 perché volevo avere il polimorfismo senza parametri. – Grault

+6

Come funziona esattamente? Come indicato qui http://stackoverflow.com/questions/15367032/member-with-the-same-signature-already-defined-with-different-type-constraints "non è possibile sovraccaricare con vincoli generici". – Miebster

5

E 'il 2017 e ora abbiamo C# 7 con pattern matching. Se il vostro tipo T Eredita object è possibile che si codice come questo

void Main() 
{ 
    DoSomething(new MyClass { a = 5 }); 
    DoSomething(new List<MyClass> { new MyClass { a = 5 }, new MyClass { a = 5 }}); 
} 


public void DoSomething(object t) 
{ 
    switch (t) 
    { 
     case MyClass c: 
      Console.WriteLine($"class.a = {c.a}"); 
      break; 
     case List<MyClass> l: 
      Console.WriteLine($"list.count = {l.Count}"); 
      break; 
    } 
} 

class MyClass 
{ 
    public int a { get; set;} 
} 
Problemi correlati