ho questi metodi di estensione e tipo enum:Perché devo posizionare() attorno all'espressione null-condizionale per usare il metodo corretto di overload?
public static bool IsOneOf<T>(this T thing, params T[] things)
{
return things.Contains(thing);
}
public static bool IsOneOf<T>(this T? thing, params T[] things) where T : struct
{
return thing.HasValue && things.Contains(thing.Value);
}
public enum Color { Red, Green, Blue }
La prima if
seguito compila; il secondo no:
if ((x.Y?.Color).IsOneOf(Color.Red, Color.Green))
;
if (x.Y?.Color.IsOneOf(Color.Red, Color.Green))
;
Esse variano solo dal gruppo di parentesi in più. Perché devo farlo?
In un primo momento ho sospettato che stava facendo un cast implicito doppia da bool?
a bool
e poi di nuovo a bool?
, ma quando rimuovo il primo metodo di estensione, si lamenta non c'è cast implicito da bool
a bool?
. Ho quindi controllato l'IL e non ci sono stati lanci. Decompilazione torna a C# rendimenti qualcosa che assomiglia a:
if (!(y != null ? new Color?(y.Color) : new Color?()).IsOneOf<Color>(new Color[2]
{
Color.Red,
Color.Green
}));
che va bene per la versione del CLR sto correndo, e quello che mi aspetto. Quello che non mi aspettavo è che x.Y?.Color.IsOneOf(Color.Red, Color.Green)
non venga compilato.
Cosa sta succedendo? È semplicemente il modo in cui è stata implementata la lingua che richiede lo ()
?
Aggiornamento
Ecco un tappo schermata che mostra l'errore nel contesto. Questo mi sta diventando ancora più confuso. L'errore ha effettivamente senso; ma quello che non (nella mia mente ora) è perché la linea 18 non avrebbe lo stesso problema.
Questo è sorprendente per me; tu * potresti * aver trovato un bug.Quello che trovo più fastidioso qui è che la risoluzione del sovraccarico sta scegliendo il secondo metodo per il caso con parens, e il primo metodo per il caso senza parens. Non mi è chiaro perché i genitori dovrebbero fare la differenza lì. –
Detto questo, vorrei riprendere i metodi di estensione qui. I metodi di estensione che estendono tutti i tipi sono spesso confusi. La cosa più comune da fare è estendere 'IEnumerable' e farlo nell'altro modo: 'var colors = new [] {Color.Red, Color.Green}; if (colors.Contains (whatever)) ... ' –
Inoltre, noto che se si desidera estendere tutto T, * è * legale da confrontare con null. 'public static bool IsOneOf (questa cosa T, params T [] cose) { return thing! = null && things.Contains (cosa); } 'è legale. –