2009-02-28 17 views
11

Quali sono le cose più importanti che si conoscono i generici: caratteristiche nascoste, errori comuni, le pratiche migliori e più utili, consigli ...cose più importanti su C# generics ... lezione imparata

sto iniziando a implementare più della mia biblioteca/API utilizzando i generici e vorrei raccogliere i modelli, i suggerimenti, ecc. più comuni trovati nella pratica.

Lasciatemi formalizzare la domanda: qual è la cosa più importante che hai imparato sui farmaci generici?

Prova a fornire esempi - sarebbe più facile da capire, al contrario di descrizioni contorte e eccessivamente secco

Grazie

questa domanda è un po 'simile a Jon's question, però, su un soggetto diverso

+0

wiki della comunità ?! –

+0

Questo dovrebbe essere un CW –

+0

Concordato con Afshari: Qualsiasi risposta accettata sarebbe una fusione di diversi post e dovrebbe essere wiki per questo scopo. Votare per chiudere fino a quando questo è il caso; favorito per tenere traccia della domanda. –

risposta

14

Una delle cose più importanti che ho imparato è che è possibile constrain the generic type parameter(s). Questo può essere molto potente, consentendo di personalizzare la classe solo per determinati tipi di oggetti e di utilizzare i membri di quel tipo nella classe generica. Mi rendo conto che questo è piuttosto fondamentale, ma è una delle cose che rende i generici incredibilmente utili.

3

Comprendere le funzionalità e le limitazioni dell'inferenza di tipo generico in C#. Una profonda comprensione di ciò che il compilatore può, e non può, dedurre in base (ad esempio) ai tipi di parametri nel tuo metodo può essere sfruttata per rendere i casi d'uso comuni della tua API significativamente più leggibili.

+1

si prega di fornire un esempio .... Mi piacerebbe vederlo in azione –

+0

La maggior parte di LINQ è un esempio, in realtà. :) Tonnellate di API generiche, ma si noti che non è quasi mai necessario specificare un tipo durante l'utilizzo. –

3

La lezione più importante sui farmaci generici che ho imparato è: più li usi meglio è.

0

Prima di tutto è inutile sapere come funziona Generics in C#. Questo article offre una buona panoramica dei generici di Anders Hejlsberg (Il padre di C#). Non penso che usarli il più spesso possibile sia così bello. Usa i farmaci generici quando hanno davvero senso. Ricorda sempre KISS e YAGNI (Keep It Simple Stupid: non ne hai bisogno) dalla programmazione estrema.

0

I tipi di delegati generici sono sempre di tipo invariante.

Mi sono imbattuto in un problema simile a quello delineato al link sottostante l'altro giorno e ha causato un po 'di confusione perché non ho capito perché dovevo trasmettere la mia raccolta.

http://www.theserverside.net/blogs/thread.tss?thread_id=47323

4

ogni specializzazione di un tipo generico viene trattato come un tipo unico quando si tratta di cose come membri statici.Ad esempio, con questo tipo:

class GenericType<T> 
{ 
    public static int SomeValue; 
} 

L'asserzione ha successo se facciamo questo:

GenericType<int>.SomeValue = 3; 
Debug.Assert(GenericType<double>.SomeValue == 0); 

Questo perché:

typeof(GenericType<int>) != typeof(GenericType<double>) 

Anche se

typeof(GenericType<int>.GetGenericTypeDefinition() == typeof(GenericType<double>).GetGenericTypeDefinition() 
1

Don So se sono più importanti, ma io ho ho appreso quanto segue:

I generici saranno istantanei solo tramite la riflessione se non si conosce il tipo frikkin. In alcuni casi potresti aver bisogno di interfacce non generiche per utilizzare le tue classi generiche in situazioni in cui il tipo è sconosciuto.

ho quasi rovinato la mia testa fino a quando ho grocked che

public class Foo<T> where T : Foo<T> { 
    public T CloneMe() ... 
} 

è perfettamente codice valido e permette la classe di base per esporre i metodi e le proprietà relative alla classe specializzata ... che ha causato la definizione di un macchina di stato lungo i suoi stati:

public abstract class Machine<S,M> where S : State<S,M> where M : Machine<S,M> { 
    protected S state; 
} 

public abstract class State<S,M> where S : State<S,M> where M : Machine<S,M> { 
    protected M machine; 
} 

I generici possono diventare un po 'ingombranti. L'altro giorno ho avuto questo:

List<Tuple<Expression<Func<DataTable,object>>,Expression<Func<DataTable,object>>>> 

uff ...

+0

Roba buona, continua a venire! –

+0

Per quanto riguarda l'ultimo snippet di codice, ho avuto qualcosa di molto simile qualche mese fa. L'ho rifattorizzato in qualcosa di un po 'più semplice e leggibile. – dotnetdev

+0

@GSS - Questo è quello che ho fatto anche io. Non è molto leggibile. Sono derivato da Tuple per questo. Proprio ora ho rifattorizzato di nuovo perché si scopre che la classe ha bisogno di più semantica :) È una vita divertente essere uno sviluppatore, sempre in movimento! – flq

1
MyGeneric<T> where T : IComparable 

non fa

MyGeneric<IComparable> 

una classe base di esso.

+0

Bene, anche se l'ho imparato, in origine, da C++ –

1

Ho appreso che i generici sono uno strumento potente e indebito, ma il loro uso improprio porta a codice molto illeggibile.

2

Nessuna covarianza o contro-varianza (almeno in 3.5). Prestare attenzione a ciò quando si progettano gerarchie di classi che includono parametri di tipo generico.

+1

Finalmente è arrivato, piccola! Si noti inoltre che CLR aveva già un certo supporto per questo (con + e - annotazioni in IL), ma le lingue e i compilatori non fornivano la sintassi per esso. –

+0

Sono stato davvero deluso dalla varianza introdotta. Penso che quello che c'è va bene, ma non va abbastanza lontano. –

2

Due lezioni interessanti. Primo; con liste; prova a pensare in termini di T; for full details see here, ma in breve è necessario utilizzare:

public void Foo<T>(IList<T> data) where T : SomeBaseClassOrInterface {} 

e non:

public void Foo(IList<SomeBaseClassOrInterface> data) {} 

Secondo: watch for the edge cases ;-p

Riesci a vedere la trappola qui?

static void Foo<T>() where T : new() 
{ 
    T t = new T(); 
    Console.WriteLine(t.ToString()); // works fine 
    Console.WriteLine(t.GetHashCode()); // works fine 
    Console.WriteLine(t.Equals(t)); // works fine 

    // so it looks like an object and smells like an object... 

    // but this throws a NullReferenceException... 
    Console.WriteLine(t.GetType()); // BOOM!!! 
} 
+0

Mark, spiega la parte Boom? È dovuto al fatto che T potrebbe essere un tipo di valore - e GetType NON è disponibile per questo? –

+0

vedi il link 'guarda per i casi limite' – johnc