2011-10-06 14 views
6

sto sperimentando con metodi di estensione fluente.Utilizzando vincoli generici con i tipi di valore

Ho il seguente metodo di estensione semplice per eseguire un cast di sicurezza.

 public static T As<T>(this Object source) 
     where T : class 
    { 
     return source as T; 
    } 

Questo funzionava bene, ma quando ho cercato di rendere intuitivo da usare valuetypes con un sovraccarico

 public static T As<T>(this ValueType source) 
     where T : struct 
    { 
     return (T)source; 
    } 

ho incontrato problemi. La logica di risoluzione del metodo sceglie sempre il primo metodo sopra riportato e fornisce un errore di sintassi (accurato) che la struct non è una classe.

C'è un modo per gestire quanto sopra, o devo seguire il percorso di rimozione del vincolo durante il test e la gestione di tutti i tipi nello stesso metodo?

Edit ====: per rispondere alle domande ====

sto compilando questo contro il framework 3.5. Non sto davvero cercando di realizzare qualcosa in particolare; questo è solo un esperimento con quanto sopra. Il mio interesse è stato commosso e ho buttato un po 'di codice.

Non sono particolarmente interessato a rimanere un cast "sicuro". È così che è iniziato, e può essere tenuto al sicuro con default() - ma questo non è veramente il punto focale della domanda e del codice per garantire che la "sicurezza" sia oscura.

Per quanto riguarda l'espressività, n. value.As<int>() non è più espressivo di (int)value; ma perché l'utente del metodo deve 'solo sapere' funziona solo con i tipi di riferimento? Il mio tentativo di farlo era più sul comportamento previsto del metodo che sulla scrittura espressiva.

Il frammento di codice value.As<DateTime>() restituisce l'errore "Il tipo 'System.DateTime' deve essere un tipo di riferimento per utilizzarlo come parametro 'T' nel tipo generico o nel metodo .... As (oggetto)" . Dal messaggio di errore vedo che si sta risolvendo a utilizzare il metodo top sopra poiché è quello che richiede il tipo di riferimento.

+0

Quale versione di C# stai usando? In .NET 4, viene selezionato il secondo sovraccarico. –

+1

Intendi codice come 'oggetto o = 42; var i = o.As (); 'che fornisce l'errore di sintassi? O potresti mostrare il codice esatto che lo dà? – svick

+0

@ il commento di svick mi viene in mente forse qualcosa che potresti tentare di fare con un risultato del database, come ad esempio un DataRow, per esempio. In tal caso, è già disponibile un metodo di estensione per convertire il valore dell'oggetto nella riga in un tipo corretto. [.Field ] (http://msdn.microsoft.com/en-us/library/bb360891.aspx) –

risposta

3

In .NET 4, il secondo di sovraccarico viene scelto in base al codice di esempio. (Anche solo testati contro .NET 3.5, stesso risultato.)

int myInt = 1; 
long myLong = myInt.As<long>(); // chooses ValueType version 

Tuttavia, questo ci ottiene solo per la scena della prossima crisi. Il (T)source; genera un'eccezione di cast non valida. Si potrebbe aggirare che scrivendo il metodo

public static T As<T>(this ValueType source) 
    where T : struct 
{ 
    return (T)Convert.ChangeType(source, typeof(T)); 
} 

Tuttavia, mi chiedo cosa si sta effettivamente cercando di raggiungere, come io non vedo il beneficio immediato. (E del resto, questo non è sicura come la versione source as T oggetto.) Per esempio, come è

long myLong = myInt.As<long>(); 

Qualsiasi più espressivo o più facile da usare rispetto

long myLong = (long)myInt; 
+0

Poiché ValueType è - nonostante il suo nome - in realtà un tipo di classe, quest'ultima formulazione richiederebbe il pugilato del discussione. Sfortunatamente, non credo che ci sia un modo per farlo. Permettere il sovraccarico basato sul valore-tipo-tipo di un parametro generico. – supercat