2015-12-05 14 views
15

Sto avendo difficoltà a capire il motivo per cui sarebbe utile per fare qualcosa di simile: (Sample è una classe)Qual è lo scopo di limitare il tipo di generico in un metodo?

static void PrintResults<T>(T result) where T : Sample 

Non sarebbe meglio passare solo campione nel metodo?

static void PrintResults (Sample result) 
+6

Per le cose passate ai metodi, il vantaggio è davvero piuttosto ridotto. Per le cose che vengono restituite di nuovo aiuta un po 'di più perché il consumatore non ha bisogno di trasmettere. – Joey

risposta

10

vi consiglio di evitare i tipi generici dove le opere di sintassi non generici, come l'esempio che ha dato. Tuttavia, ci sono altri casi utili.

Ad esempio, specificando il tipo di ritorno genericamente:

static T Create<T>() where T: Sample, new() 
{ 
    return new T(); 
} 

// Calling code 
Sample sample = Create<Sample>(); 

invece di

static object Create() 
{ 
    return new Sample(); 
} 

// Calling code 
Sample sample = (Sample) Create(); 

È inoltre possibile utilizzare i modelli per posizionare più restrizioni su un tipo. Ad esempio:

static T Create<T>() where T: IMyInterface, new() 
{ 
    return new T(); 
} 

interface IMyInterface {} 
class MyClass : IMyInterface { } 

// Calling code. 
MyClass myClass = Create<MyClass>(); 

Questo permette la creazione generico di un nuovo tipo che implementa un'interfaccia specifica e ha un costruttore generico. Inoltre:

static void DoSomething<T>(T t) where T: IMyInterface1, IMyInterface2 
{ 
    t.MethodOnIMyInterface1(); 
    t.MethodOnIMyInterface2(); 
} 

interface IMyInterface1 
{ 
    void MethodOnIMyInterface1(); 
}  
interface IMyInterface2 
{ 
    void MethodOnIMyInterface2(); 
}  
class MyClass: IMyInterface1, IMyInterface2 
{ 
    // Method implementations omitted for clarity 
} 

// Calling code 
MyClass myclass' 
DoSomething(myclass); // Note that the compiler infers the type of T. 

Dove è possibile richiedere più interfacce su un singolo parametro senza (1) la creazione di un nuovo tipo che implementa tutte queste interfacce e (2) richiedendo parametri di essere di quel tipo.

Come dice @dcastro nella sua risposta, i tipi generici possono anche indicare al compilatore di richiedere che i tipi siano gli stessi. Ad esempio:

static void DoSomething<T>(T t1, T t2) where T: MyType 
{ 
    // ... 
} 

class MyType {} 
class MyType1: MyType {} 
class MyType2: MyType {} 

// Calling code 
MyType1 myType1; 
MyType2 myType2; 
DoSomething<MyType>(myType1, myType2); 

Dove il compilatore richiede che t1 e t2 sono dello stesso tipo, ma possono essere di qualsiasi tipo che eredita MyType. Questo è utile nei framework di test unitari automatici, come NUnit o MSTest, per controlli di uguaglianza e confronto generici.

+1

Il bit alla fine della forzatura degli stessi tipi non è corretto. Ognuno di questi compilerebbe semplicemente "DoSomething (mytype1, mytype2); DoSomething ((MyType) mytype1, mytype2); '... – Brandon

+0

@akton grazie per la risposta dettagliata. Ho davvero apprezzato tutte le risposte fornite! Mi rendo conto che non ho dato il miglior esempio con cui lavorare, ma sei riuscito a rispondere bene alla domanda. Grazie ancora! – Anonymous

+0

@Brandon La domanda non è se le cose verranno compilate. I tipi generici (1) rendono il codice più facile da leggere (anche se non nel caso dell'OP) e (2) spostano più controlli in tempo di compilazione dal runtime (di solito sostituendo i cast). Nel caso specifico, questo non è il miglior esempio, ma è sufficiente per rispondere alla domanda dell'OP. – akton

2

Negli spazi vuoti si può sempre usare un'interfaccia come parametro per far funzionare più tipi, quindi i generici non sono spesso utili qui.

Solo le eccezioni sono i vincoli sui generici. E per questo non intendo qualcosa come dove T: IA, IB poiché questo potrebbe essere fatto da un'interfaccia e che entrambi implementa IA e IB. Questo a un certo punto diventerà faticoso, dal momento che avrete bisogno di sempre più interfacce. Quindi, consente di guardare ath la classe "vincoli speciale" e nuova

public void AddNew(List<T> items) where T : new 
{ 
    items.Add(new T()); 
} 

e la classe che è utile se il metodo muta il suo parametro, che non funzionerà per le strutture

static void IncA<T>(T item) where T: class, IA 
{ 
    item.A++; 
} 

La vera potenza dei farmaci generici è quando i metodi hanno un tipo di ritorno generico o classi generiche come Elenco <T>. Non vuoi implementare una nuova classe per ogni Lista di cui avrai bisogno.

3

La maggior parte delle risposte offre spiegazioni sull'utilità dei farmaci generici che coinvolgono interfacce che in realtà non sembrano affrontare la domanda effettiva.

La verità è che, per l'esempio pubblicato, non vi è alcun vantaggio nell'utilizzo di un metodo generico. In realtà è peggio perché causerà la generazione di più implementazioni della stessa funzione e aumenterà leggermente la dimensione del codice in fase di runtime.

+1

Non penso che ciò che dici di "implementazioni multiple" si applica nel suo caso perché "Sample" è necessariamente un tipo di riferimento (infatti ci dice che è un 'class'). Per i tipi di riferimento, non ci sono "implementazioni multiple". A parte questo, potresti avere ragione, non c'è molto vantaggio nel suo particolare scenario. Otteniamo un tipo aggiuntivo 'T' (che è un tipo in fase di compilazione da cui' typeof (T) 'non è necessariamente identico a' result.GetType() '). Il metodo può usare quel tipo, ad esempio 'var config = HelperClass .GetConfig();' o qualcosa del genere. –