Creare un'istanza di oggetti null con l'operatore Null-Coalescing


12

Considera il seguente scenario tipico:

if(myObject == null) {
    myObject = new myClass();
}

Mi chiedo cosa ne pensi della seguente sostituzione usando l'operatore a coalescenza nulla:

myObject = myObject ?? new myClass();

Non sono sicuro se dovrei utilizzare il secondo modulo. Sembra una bella scorciatoia, ma il myObject = myObjectcostrutto all'inizio potrebbe sembrare un po 'di odore di codice.

È una cosa ragionevole da fare o c'è una scorciatoia migliore che mi manca? O forse "Sono tre righe, superalo!"?

Modifica: Come è stato menzionato, forse chiamare questo uno scenario tipico è una sorta di sopravvalutazione. Di solito scopro di incontrare questa situazione quando sto recuperando un'entità da un database che ha una proprietà del tipo di riferimento figlio che può o non può essere ancora popolata:

myClass myObject = myClassService.getById(id);
myObject.myChildObject = myObject.myChildObject ?? new myChildClass();

15
I neofiti credono che cose del genere siano "hacker", gli sviluppatori più esperti lo chiamano semplicemente "idiomatico".
Doc Brown,

Se l'oggetto si presenta come un oggetto valore ("ha valore semantica", in termini idiomatici), MyClassdovrebbe fornire un public static readonlymembro di un Emptyvalore del suo tipo. Vedi String.Emptysu MSDN .
rwong,


5
Non c'è un ??=operatore?
aviv

1
@aviv vorrei che ci fosse!
Loren Pechtel,

Risposte:


16

Uso sempre l'operatore di coalescenza nulla. Mi piace la concisione.

Trovo che questo operatore sia di natura simile all'operatore ternario (A? B: C). Ci vuole un po 'di pratica prima che la lettura sia una seconda natura, ma una volta che ci si abitua sento che la leggibilità migliora rispetto alle versioni longhand.

Inoltre, la situazione descritta è solo uno scenario in cui l'operatore è utile. È anche utile sostituire costrutti come questo:

if (value != null)
{
    return value;
}
else
{ 
    return otherValue;
}

o

return value != null ? value : otherValue;

con

return value ?? otherValue;

Sicuramente d'accordo in generale sull'uso di questo operatore. Quando vedo riferimenti all'utilizzo, tuttavia, in genere è qualcosa di simile myObject = myObject2 ?? myObject3. Quello che mi chiedo in particolare è usare l'operatore per impostare un oggetto su se stesso a meno che non sia nullo.
grin0048,

2
Penso che lo stesso ragionamento si applichi in entrambi i casi. È un modo più conciso per esprimere la stessa logica.
17 del 26

Ricordo di aver guardato l'IL per ognuna di quelle tre forme una volta. Il primo e il secondo erano identici, ma il terzo è stato ottimizzato in modo da poter supporre che nullfosse un confronto.
Jesse C. Slicer,

2

Quello che mi chiedo in particolare è usare l'operatore per impostare un oggetto su se stesso a meno che non sia nullo.

Si ?? operatorchiama operatore a coalescenza nulla e viene utilizzato per definire un valore predefinito per tipi di valore nullable o tipi di riferimento. Restituisce l'operando di sinistra se l'operando non è nullo; altrimenti restituisce l'operando giusto.

myObject = myObject ?? new myObject(); - instantiate default value of object

Maggiori dettagli e esempio di codice sull'operatore a coalescenza nulla - articolo MSDN .

Se si verifica la more than nullablecondizione, in alternativa è possibile utilizzare l'operatore Ternario.

Operatore ternario

Puoi anche consultare ?: Operatore . Si chiama Ternario o operatore condizionale . L'operatore condizionale (? :) restituisce uno dei due valori in base al valore di un'espressione booleana.

Un tipo nullable può contenere un valore o può essere indefinito. Il ?? l'operatore definisce il valore predefinito da restituire quando un tipo nullable è assegnato a un tipo non nullable. Se si tenta di assegnare un tipo di valore annullabile a un tipo di valore non annullabile senza utilizzare ?? operatore, genererai un errore in fase di compilazione. Se si utilizza un cast e il tipo di valore nullable è attualmente indefinito, verrà generata un'eccezione InvalidOperationException.

Un esempio di codice da MSDN -?: Operator (Riferimenti per C #) :

int? input = Convert.ToInt32(Console.ReadLine());
string classify;

// ?: conditional operator.
classify = (input.HasValue) ? ((input < 0) ? "negative" : "positive") : "undefined";

Quindi prendendo l'esempio dalla domanda e applicando l'operatore condizionale, avremmo qualcosa di simile myObject = (myObject == null) ? new myClass() : myObject. Quindi, a meno che non mi manchi un uso migliore dell'operatore condizionale, sembra avere lo stesso "problema" con l'impostazione di un oggetto su se stesso (se non è nullo) dell'operatore a coalescenza nulla - ed è meno conciso.
grin0048,

Se si sta verificando più di una condizione (non nulla e maggiore di zero), l'operatore condizionale lo farà. Tuttavia, solo il controllo null funzionerebbe per ?? operatore.
Yusubov,

2

Non penso che lo scenario sia (o almeno dovrebbe essere) tipico.

Se si desidera che il valore predefinito di alcuni campi non sia null, quindi impostarlo nell'inizializzatore di campi:

myClass myObject = new myClass();

Oppure, se l'inizializzazione è più complicata, impostala nel costruttore.

Se vuoi creare myClasssolo quando ne hai effettivamente bisogno (ad es. Perché crearlo richiede molto tempo), puoi usare Lazy<T>:

Lazy<myClass> myObject = new Lazy<myClass>();

(Questo chiama il costruttore predefinito. Se l'inizializzazione è più complicata, passa lambda che crea myClassal Lazy<T>costruttore.)

Per accedere al valore, utilizzare myObject.Value, che chiamerà l'inizializzazione se è la prima volta che si accede myObject.Value.


La creazione pigra IMO è utile solo se non hai la garanzia di aver bisogno dell'oggetto risultante, solo il tempo in cui utilizzo la creazione pigra è quando ho un risultato derivato incassato che ripristino quando qualcosa cambia e so che avrò bisogno dello stesso risultato molto e il ricalcolo è costoso. altro saggio, non voglio preoccuparmi del controllo null
maniaco del cricchetto,

@ratchetfreak Sì, ecco perché ho suggerito prima l'inizializzatore di campo.
svick,

Ci sono anche altri casi. Quello che sto guardando al momento: il primo passaggio imposta i casi di eccezione. Il secondo passaggio imposta le impostazioni predefinite per tutto il resto. ?? = taglierebbe la linea a metà.
Loren Pechtel,

1

Mi piace in particolare l'utilizzo ??in combinazione con parametri di metodo opzionali. Limito la necessità di sovraccarichi e mi assicuro che la cosa abbia un valore.

public void DoSomething (MyClass thing1 = null) {
    thing1 = thing1 ?? new MyClass();
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.