2015-01-13 13 views
23

Mi sono imbattuto in un sito interessante, in cui vengono affrontate alcune delle nuove funzionalità (proposte) di C# 6.0. Puoi leggerlo qui: Probable C# 6.0 features.Controllo null monadico in C# 6.0

Quello che trovo particolarmente interessante è il controllo null monadico (noto anche come operatore di propagazione null ?.). Secondo il sito, la seguente dichiarazione

var bestValue = points?.FirstOrDefault()?.X ?? -1; 

contiene il controllo di nulla monade, che è attualmente implementato con questo pezzo di codice:

if (points != null) 
{ 
    var next = points.FirstOrDefault(); 
    if (next != null && next.X != null) return next.X; 
} 
return -1; 

Il mio primo sguardo era, hey, quello che è scritto diamine Qui? Ma dopo aver visto il "vecchio" codice, sto iniziando a piacermi.

Tuttavia, sto anche iniziando a ricevere alcune domande, che vorrei chiedere.

  • Suppongo che questo operatore con propagazione nulla sia thread-safe. Ma come viene effettivamente eseguito? Le condizioni di gara saranno rimosse o persistono?
  • In che modo questo operatore gestisce i tipi generici? Inoltre, come gestirà i tipi generici non vincolati? Ad esempio, si consideri

    var resultAfterNullCheck = x?.Y; 
    

    Se il tipo Y qui viene istanziata con tipi di riferimento, tipi di valore non annullabili e tipi di valore nullable, non ci sarebbe nulla ragionevole fare (poichè non posso pensare a cosa fare, come Semplicemente non so cosa fare). Quindi c'è un valore predefinito che verrà restituito? O genererà un errore?

  • Osservando l'esempio fornito dal sito (e che ho copiato sopra) presumo che uno dei principali vantaggi dell'operatore di propagazione nullo sarà che valuterà l'istruzione solo una volta. Tuttavia (forse a causa della mia mancanza di conoscenza di CLR), sono abbastanza curioso su come potrebbe essere eseguita.
    Per quanto mi riguarda, la prima valutazione (se i punti equivalgono a null) deve attivare il metodo di estensione FirstOrDefault() per l'attivazione quando i punti non sono nulli, seguito dalla valutazione del tipo restituito da null o no, in caso contrario, X sarà restituito. Quindi queste sono in realtà tre valutazioni combinate in una? O lo sto capendo in modo errato? Ciò influenzerà la velocità di esecuzione?

In altre parole, cosa sarà più veloce, il vecchio modo di eseguire i controlli nulli o questo nuovo operatore adorabile? Cercherò di esaminare questo facendo qualche ricerca non appena il download di Visual Studio 2015 è finito ... Ma questo richiede un po 'di pazienza ...

Ci sono pensieri su questo nuovo tipo di operatore? E 'davvero ancora una proposta, o possiamo davvero aspettarci di lavorare con questo nuovo assegno nulla monadico?

EDIT
Come Matthew Watson fornito una bella MSDN article discutere di questo argomento (s) (e più), ero curioso se menzionato la mia precedente domanda per quanto riguarda i farmaci generici non vincolati e come questo operatore con offerte che. Sfortunatamente, non ho ancora trovato una risposta. Mentre suppongo che il programmatore dovrebbe cercare di prevenire l'uso di generici non vincolati, posso ancora immaginare che a volte questo non sia fattibile. Se questo è il caso, sarà davvero necessaria una riprogettazione?

+2

Si chiama ["Null condizionale operator"] (http://blogs.msdn.com/b/csharpfaq/archive/2014/11/20/new-features-in-c-6.aspx) ora. –

+1

Puoi trovare molte informazioni qui https://roslyn.codeplex.com/discussions/540883. – adrianm

+2

@MatthewWatson 'if (MyEvent! = Null) MyEvent (this, EventArgs.Empty);' è un noto esempio di ciò che dovrebbe essere riscritto come 'var myEvent = MyEvent; if (myEvent! = null) myEvent (this, EventArgs.Empty); ': anche se l'accesso a' MyEvent' è atomico, potrebbe passare da non null a null tra il confronto e l'invocazione. Questo è il tipo di cosa che 'MyEvent? .Invoke (this, EventArgs.Empty);' dovrebbe già occuparsi, come ho capito. – hvd

risposta

14

Si sta pensando troppo a questo. Uno ad uno, le tue domande:

  1. Perché dovresti pensare che sia sicuro? Chiamare una funzione membro non lo è. Questo non è altro che chiamare una funzione membro con un pre-controllo per i null, in modo da ottenere solo la sicurezza del thread quanto la funzione originale garantisce.

  2. Se il tipo generico consente il confronto nullo (che è ciò che questo operatore utilizzerà dietro le quinte), verrà emesso il codice. In caso contrario riceverai un errore di compilazione (ad esempio se richiedi che il tipo sia un tipo di valore). Questo copre tutti i casi!

  3. Si chiama operatore una volta per operatore, proprio come il normale operatore .. Se dici A.b.c ci saranno ancora due livelli di riferimento indiretto, e l'utilizzo di questo nuovo operatore non è nulla di diverso, ma controlla anche i valori null.

i reali benefici di ?. sono che è semantica (si può dire a colpo d'occhio ciò che il codice sta cercando di fare) e corto circuito (rende il codice molto più breve rispetto annidato if s). Non sostituirai ogni . nel tuo vecchio codice con ?., infatti probabilmente lo utilizzerai raramente. Ma ci sono casi in cui sarà utile, come nelle espressioni Linq che seguono le operazioni ...OrDefault() o chiamando eventi.

+3

È davvero necessario? Non credo che qualcuno si aspetti che 'x? .f' possa creare magicamente' f' threadsafe. Stava solo chiedendo se 'x? .f' rimuove la condizione di gara in' if (x.f! = Null) x.f'. – Rawling

+4

Ho sentito prima che sto pensando troppo a cose. Anche mia moglie si lamenta per questo. Immagino che abbia qualcosa da fare che sto cercando di capire come stanno funzionando i meccanici prima di provarli. @Rawling ha ragione con ciò che intendevo con la mia prima domanda. Modificherò la mia domanda. – RvdV79

+0

@Rawling, non credo che lo fosse, se si guarda al suo codice si vede che capisce già che la variabile viene prima salvata nello stack, quindi testata, quindi utilizzata. – Blindy

1

È possibile trovare tutto ciò che riguarda le funzionalità pianificate nella discussione del progetto Roslyn. È anche possibile provare le nuove funzionalità con l'applicazione console utilizzando Roslyn come NuGet-package (che significa che funziona con Visual Studio 2013 <)

6

Per rispondere parzialmente la prima domanda, in base a John Skeet on his blog, l'operatore condizionale nullo ?. (= operatore di propagazione null) è thread-safe.

+0

come è sicuro il thread dell'operatore se lo scrittore del blog menziona utilizzando Interlocked.CompareExchange per renderlo thread-safe? Voglio dire, potrebbe essere, ma non ho visto alcuna prova di ciò nel post del blog che hai menzionato, mi sono perso qualcosa? –

+1

"Il codice che abbiamo ottenuto finora è" thread-safe "in quanto non importa ciò che fanno gli altri thread - non otterrai una NullReferenceException dal codice precedente." Nel frattempo, 'Interlocked.CompareExchange' è utile "per invocare l'ultimo set assoluto di sottoscrittori di eventi". Quindi non si tratta di sicurezza dei thread, ma se si desidera assicurarsi che l'evento venga attivato sull'insieme più recente di sottoscrittori di eventi. –

+0

L'operatore valuta fondamentalmente un metodo che accetta x, verifica la nullità e, se non è null, esegue il seguente codice su x. Se si chiama un metodo con una variabile membro e la variabile membro immediatamente dopo è impostata su null, la variabile nel metodo avrà ancora un oggetto reale. In questo senso ?. è thread-safe –