2014-12-04 16 views
5

Desidero assegnare in modo condizionale un valore a una variabile se la variabile è già null. Inoltre, se questa variabile non è già null Voglio che lo non compaia nulla e voglio essere in grado di fare tutto con un solo operatore.Operazione di assegnazione che non fa nulla se la variabile è nulla?

object a = null; 
object b = new Something(); 

// this is essentially what I want but done with an operator: 
if(a == null) 
{ 
    a = b; 
} 

// this is all I feel I have to work with, 
a = a || b; 
a = a ?? b; 
a = a == null ? b : a; 

// the above methods all end up performing a = a if a is not null 
+5

Quindi presumo 'a = a ?? b; 'è uscito? –

+1

@JoelRondeau Appare così - OP non vuole che 'a' venga assegnato a se stesso. –

+0

'if (a == null) a = b;' Se non vuoi che 'a' venga assegnato a' a' probabilmente dovrai usare un'istruzione 'if'. – heavyd

risposta

6

se sei preoccupato di fare tutto questo in una singola istruzione, sei sfortunato: C# non ha questa funzionalità a livello linguistico e non supporta la dichiarazione dell'operatore (come fa F #) o il sovraccarico dell'operatore di assegnazione (come fa C++). Ci sono, tuttavia, un paio di opzioni, se nessuna abbastanza elegante come richiesto.

Il if dichiarazione, come lei ha ricordato, anche se può essere scritto una sola riga

if(a == null) a = b; 

un metodo di supporto che sarà non utilizza un parametro ref

public void AssignIfNull<T>(ref T target, T value) 
{ 
    if(target == null) target = value; 
} 

// ... 

AssignIfNull(ref a, b); 

Nota quanto sopra lavorare con una proprietà, poiché non possono essere passati come parametro ref.

EDIT: Mentre quanto precede è simile a Interlocked.CompareExchange, tale alternativa restituisce il valore originario del primo parametro, quindi potrebbe rivelarsi più di un Gotcha di attuazione del metodo di cui sopra.

Oppure è possibile riscrivere attentamente l'istruzione iniziale per utilizzare un operatore null-coalescing (??) nell'assegnazione iniziale.

3

Come hai detto, una dichiarazione if è ciò di cui hai bisogno. Non esiste un operatore condizionale che non assegni quando null. Un if è il più adatto in questo caso (non tutto deve essere un oneliner).

Le migliori opzioni:

if(a == null) 
{ 
    a = b; 
} 

O:

a = a ?? b; 

In realtà, credo che quest'ultimo è ottimizzato via come un semplice if dichiarazione.

Assegnare a a se stesso non è male. Con i riferimenti agli oggetti, è solo un'assegnazione dell'indirizzo di memoria. Per i tipi di valore, questo è solo un piccolo frammento di dati.

Se a è in realtà un setter di proprietà, controllare all'interno della setter il valore contiene modifiche:

private string a; 

public string A 
{ 
    get 
    { 
     return a; 
    } 
    set 
    { 
     if (value != a) 
     { 
      a = value; 
     } 
    } 
} 
+1

'a = a' attiva ancora il metodo' set' dell'oggetto? Non voglio davvero che venga attivato. – LCIII

+0

Oh, mi dispiace, mio ​​male. :) – Andrew

1

Anche se la sintassi è prolisso

(a==null?()=>a=b:(Action)(()=>{}))(); 

Dividiamolo parte

(       // Expression starts here 
    a == null    // If a == null... 
     ?() => a = b  // return lambda that assigns a = b 
     : (Action) (  // Else return next lambda casted as Action 
      () => {}  // Empty lambda that does nothing 
     )     // End cast 
)       // Expression ends here 
();       // Execute it! 

Ad ogni modo vorrei usare il solo rivestimento se if(a == null) { a = b; }

+2

Perché il downvote? questo fa esattamente quello che l'OP ha chiesto a –

+2

Non ho fatto downvote, ma questo è solo un modo oscuro per fare un 'if'. In effetti il ​​'?' Lo fa. –

+0

La differenza è? restituisce un'espressione che deve essere assegnata ad alcune variabili. l'unico modo per sbarazzarsi di quella variabile è quello di renderlo restituito lambda ed eseguirlo come funzioni autoeseguenti di javascript –

1

Come una singola istruzione,

var result = ((a == null) ? (a = b) : null); 

Il valore di result possono poi essere scartate. Avere a e b come proprietà dell'oggetto e aggiungere Console.WriteLine() all'impostazione per a mostrerà che è assegnato solo quando era precedentemente null.

L'unica cosa che impedisce di essere perfettamente pulito è che viene creata una variabile throwaway result; speriamo che sia ancora abbastanza pulito.


Addendum - Ho appena realizzato è anche possibile utilizzare:

var result = a ?? (a = b); 

come una versione ancora più breve di quanto sopra. Nuovamente, a = b viene valutato solo se a è null.

2

Avendo incontrato personalmente questa situazione, ho deciso di controllare il mio codice in cui mi occupo di questo. Tendo ad avere due soluzioni, entrambe coinvolgono l'operatore coalescente null.

Caso 1: inizializzazione. Utilizzando i valori dall'alto, questo diventa:

object a = null ?? something; 

Ovviamente, non vorrei scrivere che riga di codice (ReSharper si lamentano se non altro). Ma è l'essenza di ciò che sta accadendo. Se ho i due (o più) valori disponibili quando creo a, allora lo scrivo in questo modo.

Caso 2: Non impostare mai a, ma utilizzare ?? quando viene utilizzato a. In questo caso, il codice sarebbe:

MethodTakingA(a ?? b); 

Se non ci sono chiamate a metodi multipli o altri luoghi in cui avevo bisogno di usare ??, allora questa è una cattiva idea.

C'è un terzo caso in cui faccio esattamente l'incarico che stai evitando. Questo è quando uno dei parametri del mio metodo potrebbe essere nullo, e ho un valore predefinito da usare in quel caso (al contrario di lanciare un ArgumentNullException). Ecco un esempio:

public void Foo(string str) 
{ 
    str = str ?? String.Empty; 
    //Use str as needed below without fear that it might be null. 
} 

Vorrei una risposta migliore per questo caso, ma io non sono di certo la scrittura di codice in cui micro-ottimizzazione che l'assegnazione vale la pena, e la risposta teorica di

string localStr = str ?? String.Empty; 

È appena aggiunta una nuova variabile per aggiungerne una. Altrimenti non mi serve per nulla, quindi tengo il mio incarico e vivo con esso.

Problemi correlati