Operatore e generiche classi
-
22-08-2019 - |
Domanda
.NET On-the-Fly compilatore per lo scripting CLR e vogliono metodo di esecuzione rendono accettabile generica :
object Execute()
{
return type.InvokeMember(..);
}
T Execute<T>()
{
return Execute() as T; /* doesn't work:
The type parameter 'T' cannot be used with the 'as' operator because
it does not have a class type constraint nor a 'class' constraint */
// also neither typeof(T) not T.GetType(), so on are possible
return (T) Execute(); // ok
}
Ma penso operatore as
sarà molto utile: se il tipo di risultato non è il metodo T
tornerà null
, invece di un'eccezione! E 'possibile fare?
Soluzione
È necessario aggiungere
where T : class
per il vostro dichiarazione di metodo, per es.
T Execute<T>() where T : class
{
Tra l'altro, come un suggerimento, che wrapper generico in realtà non aggiunge molto valore. Il chiamante può scrivere:
MyClass c = whatever.Execute() as MyClass;
In alternativa, se vogliono gettare su fallire:
MyClass c = (MyClass)whatever.Execute();
Il metodo wrapper generico simile a questo:
MyClass c = whatever.Execute<MyClass>();
Tutte e tre le versioni hanno di specificare esattamente le stesse tre entità, solo in ordine diverso, in modo che nessuno sono affatto più semplice o più conveniente, ma la versione generica nasconde ciò che sta accadendo, mentre le versioni "grezzi" ogni mettere in chiaro se ci sarà un lancio o un null
.
(Questo può essere irrilevante per voi se il vostro esempio è semplificato dal codice vero e proprio).
Altri suggerimenti
Non è possibile utilizzare l'operatore as
con un tipo generico senza alcuna restrizione. Dal momento che l'operatore utilizza as
nulla per rappresentare che non era del tipo, non è possibile utilizzarlo su tipi di valore. Se si desidera utilizzare obj as T
, T
sarà sono per essere un tipo di riferimento.
T Execute<T>() where T : class
{
return Execute() as T;
}
Questo piccolo pezzo di codice è una sostituzione sicura un'eccezione per il come -parola chiave:
return Execute() is T value ? value : default(T)
Si utilizza la funzione di pattern matching introdotta con C # 7. Usalo, se non si desidera limitare il parametro generico per un tipo di riferimento
Sembra che si stia semplicemente aggiungendo un metodo wrapper per la fusione del tipo che l'utente desidera, quindi solo l'aggiunta di spese generali per l'esecuzione. Per l'utente, la scrittura
int result = Execute<int>();
non è molto diverso da
int result = (int)Execute();
È possibile utilizzare il il modificatore di scrivere il risultato in una variabile di portata del chiamante, e restituire un flag booleano per dire se è riuscito:
bool Execute<T>(out T result) where T : class
{
result = Execute() as T;
return result != null;
}
C'è una possibilità che execute () potrebbe restituire un tipo di valore? Se è così, allora è necessario il metodo di Earwicker per i tipi di classe, e un altro metodo generico per i tipi di valore. Potrebbe essere simile a questo:
Nullable<T> ExecuteForValueType<T> where T : struct
La logica interna che metodo direbbe
object rawResult = Execute();
Quindi, dovreste ottenere il tipo di rawResult e vedere se può essere assegnato a T:
Nullable<T> finalReturnValue = null;
Type theType = rawResult.GetType();
Type tType = typeof(T);
if(tType.IsAssignableFrom(theType))
{
finalReturnValue = tType;
}
return finalReturnValue;
Infine, rendere il vostro originale Esegui figura messaggio fuori che T è ha (classe o struct tipo), e chiamare l'implementazione appropriata.
Nota: Questo è dalla memoria massima. Ho fatto questo circa un anno fa e, probabilmente, non ricordo ogni dettaglio. Ancora, spero che punta nella direzione generale, aiuta.