aggiornamento: questo non è più un problema da C# 6, che ha introdotto l'operatore
nameof
per affrontare tali scenari (vedi MSDN).espressioni Lambda per refactoring-safe ArgumentExceptionNota: Fare riferimento a "Getting names of local variables (and parameters) at run-time through lambda expressions" per una generalizzazione di questa domanda, nonché alcune risposte.
mi piace l'idea di usare espressioni lambda per creare implementazioni refactoring di sicurezza dell'interfaccia INotifyPropertyChanged
, utilizzando codice simile a quello fornito da Eric De Carufel.
Sto sperimentando l'implementazione di qualcosa di simile per fornire il nome del parametro a un ArgumentException
(o le sue classi derivate) in modo sicuro per i refactors.
ho definito il seguente metodo di utilità per l'esecuzione di null
controlli:
public static void CheckNotNull<T>(Expression<Func<T>> parameterAccessExpression)
{
Func<T> parameterAccess = parameterAccessExpression.Compile();
T parameterValue = parameterAccess();
CheckNotNull(parameterValue, parameterAccessExpression);
}
public static void CheckNotNull<T>(T parameterValue,
Expression<Func<T>> parameterAccessExpression)
{
if (parameterValue == null)
{
Expression bodyExpression = parameterAccessExpression.Body;
MemberExpression memberExpression = bodyExpression as MemberExpression;
string parameterName = memberExpression.Member.Name;
throw new ArgumentNullException(parameterName);
}
}
convalida argomento può quindi essere effettuati in modo refactoring di sicurezza utilizzando la seguente sintassi:
CheckNotNull(() => arg); // most concise
CheckNotNull(arg,() => args); // equivalent, but more efficient
mia preoccupazione bugie nelle righe seguenti:
Expression bodyExpression = parameterAccessExpression.Body;
MemberExpression memberExpression = bodyExpression as MemberExpression;
A MemberExpression
rappresenta "accesso a un campo o proprietà". È garantito che funzioni correttamente nel caso INotifyPropertyChanged
, poiché l'espressione lambda sarebbe un accesso di proprietà.
Tuttavia, nel mio codice sopra, l'espressione lambda è semanticamente un parametro accesso, non un campo o accesso alla proprietà. L'unica ragione per cui il codice funziona è che il compilatore C# promuove qualsiasi variabile locale (e parametri) catturata in funzioni anonime per le variabili di istanza all'interno di una classe generata dal compilatore dietro le quinte. Questo è corroborato da Jon Skeet.
La mia domanda è: questo comportamento (di promozione dei parametri acquisiti in variabili di istanza) è documentato all'interno delle specifiche .NET, oppure si tratta solo di dettagli di implementazione che possono cambiare in implementazioni alternative o versioni future del framework? In particolare, potrebbero esserci ambienti in cui parameterAccessExpression.Body is MemberExpression
restituisce false
?
Che dire di 'CheckNotNull (() => ((oggetto) 5) come stringa);'? – leppie
Personalmente ho deciso che qualunque cosa 'Contract.Requires' è abbastanza buono per me. Se una precondizione fallisce, è un bug. Non c'è bisogno di preoccuparsi per i dettagli. –
CodesInChaos
@CodeInChaos: che dire delle librerie che saranno rese disponibili per il consumo a terze parti? È previsto che i metodi pubblici eseguano il controllo degli argomenti e generino 'ArgumentException' con il nome del parametro corretto. – Douglas