2013-03-14 8 views
31

Mi sono imbattuto nel bellissimo delegato Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, TResult> in C# .NET 4.5 oggi. Presumo che 16 fosse un luogo arbitrario da fermare (quali metodi hanno più di 16 parametri?) Ma mi ha fatto pensare: è possibile in C# specificare che un tipo generico può avere un numero qualsiasi di argomenti tipo? in modo simile che la parola chiave params per metodi consente un numero qualsiasi di argomenti per un metodo. Qualcosa di simile a questo:Utilizzo della parola chiave "params" per i parametri generici in C#

public class MyInfiniteGenericType<params T[]> { ... } 

dove all'interno della classe si potrebbe quindi accedere agli argomenti di tipo enumerando attraverso di loro o utilizzando T[index] nello stesso modo in cui params permette all'interno dei metodi.

Non l'ho mai usato personalmente, ma il delegato di Func sarebbe un posto perfetto per usarlo. Non ci sarebbe bisogno di 16 diversi tipi di Func!

Quindi la mia domanda è, questo può essere fatto in qualsiasi modo in C#, e se non è un'idea stupida?

+0

Discusso tangenzialmente altrove su SO: http://stackoverflow.com/a/4046525/63225 – sblom

risposta

29

è possibile in C# specificare che un tipo generico può avere un numero qualsiasi di argomenti tipo?

No, C# non ha niente del genere, ho paura.

Fondamentalmente Func<T> e Func<T1, T2> sono tipi completamente indipendenti per quanto riguarda il CLR, e non c'è niente come params per specificare più argomenti di tipo.

Per quanto riguarda la sua utilità: posso vedere casi in cui potrebbe essere utile, ma sospetto che siano abbastanza rari da significare che la funzione non supera la soglia "beneficio/costo". (Si noti che quasi certamente richiederebbe anche modifiche CLR.)

+2

Mi sono imbattuto in un caso per questo oggi e stavo cercando di vedere se fosse possibile. Non credo che una cosa del genere dovrebbe essere omessa a causa del costo/beneficio. Voglio dire che un metodo di tipo generico di 16 è brutto ... e sono disposto a scommettere che quasi nessuno lo sta usando, quindi il tempo trascorso a cuocerlo nel quadro è stato uno spreco. –

+2

@rushonerok: Il costo di metterlo nel framework è davvero molto basso e, sebbene non venga usato dal codice * manual *, viene utilizzato nella digitazione dinamica. Il costo di cambiare la lingua per supportare questa richiesta di funzionalità è molto, molto più alto. –

2

No, non è possibile avere un numero arbitrario di argomenti generici. Probabilmente è anche un'idea sciocca, perché i parametri di tipo generico non vengono risolti in fase di runtime, sono risolti in fase di compilazione e quindi iterare su di essi in quel modo non è affatto una cosa ovvia da fare.

Si potrebbe anche pensare che Tuple < ,,,,,,,,> potrebbe essere un posto ovvio per questo, ma la soluzione è quando si esauriscono argomenti generici, si rende l'ultima una tupla <, ,,,> per i campi rimanenti.

7

C++ 11 ha la caratteristica di cui si sta essenzialmente parlando. Lo chiamano variadic templates.

I generici di C# non sono proprio come i modelli C++, tuttavia, e renderebbero difficile creare la stessa cosa.

Nel caso C++, i modelli vengono espansi in fase di compilazione in tutti i tipi di calcestruzzo utilizzati. Nel caso C#, la specifica del tipo avviene interamente in fase di esecuzione. E l'IL risultante avrebbe bisogno di supportare il numero di diversi tipi incontrati.

1

No, non è possibile.

Non è così semplice come trattarlo come una serie di tipi (un concetto che non esiste nemmeno in C#). Considerare Func - il numero di parametri di tipo deve essere uguale al numero di parametri del metodo Invoke del delegato. Ma come potrebbe il programmatore esprimere una tale relazione tra parametri di tipo e parametri regolari?

Tuttavia, questa funzione esiste in C++ 11 - variadic templates. Si noti che C++ non consente l'accesso ai singoli parametri di tipo usando la sintassi dell'array - invece, le funzioni solitamente separano il primo parametro di tipo dal resto, e usano le chiamate ricorsive per decomprimere il resto.

0

Mi sono appena trovato curioso di vedere se qualcun altro ha avuto un uso per questo. Ho appena scritto un compositore generico per costruire compositi da mixins assemblati usando Castle Dynamic Proxy.

ho costruito al compositore di supportare due mixins e stava per proseguire sulla "copia e incolla e regolazione (bleh)" due compositore mixin in altre 15 varianti fino ad un 17 compositore miscelazione (simile a Func<T> attraverso Func<T1...T16, T>). Ma poi ho pensato, non sarebbe bello se potessi semplicemente definire Composer<TComposer, TIComposite, params[] TIMixin>!

Purtroppo, sono fuori per copiare e incollare e regolare via (l'attività che i farmaci generici ci aiutano ad evitare).

Problemi correlati