Fino a che punto 'var' e null coalescing operator '??' essere intrattenuti senza ostacolare la leggibilità?


23

So che il titolo della domanda è molto soggettivo, ma mi sono confrontato con l'uso ??dell'operatore da parte dei miei colleghi, dove allo stesso tempo non ero molto contento / a mio agio nell'applicare il varnuovo codice emergente.

L'argomento fornito per l'utilizzo ??dell'operatore era che toglie la leggibilità nel codice.

La mia domanda è: non succede la stessa cosa quando inizi a usare var?


49
Se uno "sviluppatore" non riesce a capire l' ??operatore di coalescenza nulla dopo che è stato spiegato, non dovrebbe essere autorizzato vicino al codice di produzione.
CaffGeek,

12
Suggerisco di cambiare l'operatore da ?? a IfNullThen. ? può essere IfSoChoose,: is ElseChoose. + è Aggiungi. - è Sottrai, a meno che non sia unario, quindi è Negativo. - è diviso tra DecrementBeforeUsing e DecrementAfterUsing. In C ++ puoi farlo con le macro.
Lee Louviere,

7
@Xaade: questa è ironia, vero? ... destra? ... Dio, lascia che sia ironia (e io sono un ateo).
Steven Jeuris,

10
@StevenJeuris Potrebbe essere il sarcasmo , ma non è ironia .
Kirk Broadhurst,

1
@KirkBroadhurst: mi correggo , ho sempre confuso quei due.
Steven Jeuris,

Risposte:


53

Operatore a coalescenza nulla (??)

Personalmente, non vedo alcun aspetto negativo nell'utilizzare questo operatore. Considera i seguenti tre esempi di codice, da nuovi operatori "facili" a "complessi".

Senza magia:

bool isNameSet = false;
string name;
if ( isNameSet )
{
    Console.WriteLine( name );
}
else
{
    Console.WriteLine( "No name set." );
}

Operatore ternario:

bool isNameSet = false;
string name;
Console.WriteLine( isNameSet ? name : "No name set." );

Coalescenza nulla:

string name = null;
Console.WriteLine( name ?? "No name set." );

Il motivo per cui questi operatori sono stati inventati è perché rappresentano operazioni di programmazione molto comuni . Non volerli usare perché non ci sei abituato è solo essere testardo . Le lingue si evolvono, le funzionalità si evolvono, imparano ad usarle!

parola chiave var

Ho un'opinione leggermente diversa sulla parola chiave var. Il tipo di una variabile fornisce spesso informazioni aggiuntive sul codice. Trovo che nascondere il tipo usando la parola chiave var talvolta renda il codice meno leggibile. Sai meno cosa aspettarti senza utilizzare il completamento automatico o passando con il mouse sopra gli identificatori per vedere cosa sono realmente. Secondo me, questo porta a un codice che è più lento da leggere / scrivere.

Uso la parola chiave quando scopro che il tipo non fornisce molte informazioni extra.

  • Principalmente nei cicli foreach , che ho imparato da Resharper in quanto è un'ambientazione lì. Il più delle volte, sai quale tipo di collezione stai attraversando, quindi sai che ti aspetti articoli da quella collezione.
  • Query Linq . Il risultato delle query linq sono spesso tipi generici molto complessi. Visualizzare questo tipo fa più male che bene.
  • Nomi di caratteri lunghi che sono semplicemente inizializzati con il loro costruttore. Puoi già capire di che tipo si tratta guardando il costruttore.

Come esempio per l'ultima affermazione:

ThisIsSomeSpecializedTypeRightHere duplication =
    new ThisIsSomeSpecializedTypeRightHere();
var justAsReadable =
    new ThisIsSomeSpecializedTypeRightHere();  // Less duplication.

// But I still prefer the following ...
int number = 9;
SomeCreatedType foo = Factory.CreateSomeType();

24
L'ultimo esempio è esattamente quando la parola chiave var può eccellere. Immagina che il codice sia disseminato in tutto il tuo codice. Factory.CreateSomeTyperitorna IEnumerable<SomeType>. Un giorno, per qualsiasi motivo, cambia per tornare SomeType[]. Se hai usato var, è solo una ricompilazione.
pdr

1
Ho preso quell'esempio nel modo sbagliato e poi sono andato a cercare cibo. Numpty! Un esempio migliore sarebbe usare il tuo. Cosa succede se le Factory.CreateSomeType()modifiche restituiscono un ISomeType?
pdr

4
@pdr: molto probabilmente ciò significa che anche l'interfaccia è cambiata e anche il comportamento deve essere modificato / aggiunto. Se si tratta di una semplice ridenominazione, è possibile che la ridenominazione sia automatizzata. Se il "contratto" cambia, preferisco vedere il mio codice non funzionare in modo da poter vedere se devo modificare qualcosa o meno.
Steven Jeuris,

2
Penso che sia molto più probabile che se restituire un tipo concreto diventi restituire un'interfaccia, ciò sta semplicemente consentendo ad altri tipi concreti con la stessa interfaccia (coerentemente con il modello Factory). Ma se il contratto cambia, il tuo codice si romperà, anche se potresti trovarlo solo in alcuni casi in cui è importante piuttosto che ovunque.
pdr

1
@ Tom Hawtin, sappiamo tutti che è inevitabile evitarlo del nulltutto. Inoltre, più cerco alternative null, più realizzo che l'utilizzo nullè talvolta la soluzione più pulita. Il mio esempio dato non è poi così male IMHO, e trovo un uso appropriato di tipi nullable.
Steven Jeuris,

16

var consente un codice meno dettagliato, che aumenta la leggibilità. Secondo me, la leggibilità non dovrebbe essere misurata da quanti dettagli vedi, ma quanti dettagli sono nascosti a prima vista. Oltre agli esempi Linq, var consente la tipizzazione duck a livello di codice sorgente, dato il seguente esempio:

...
foreach (var message in messages) {
  var label = Factory.CreateLabel();
  label.Text = message;
  Controls.Add(label);
}
...

A chi importa qual è il tipo di etichetta purché fornisca la proprietà Text?


Qualcuno sta cercando di capire se si tratta ad esempio di un'etichetta winforms o di un'etichetta WPF.
Steven Jeuris,

14
@Steven Jeuris: di solito si tratta di un'informazione di contesto nota. In caso contrario, ti stai avvicinando al codice in modo errato.
Codismo

Qualcuno che vuole sapere se si tratta di un'etichetta WPF predefinita o di un'etichetta personalizzata allora? :)
Steven Jeuris,

14
1. A quella persona dovrebbe interessarsene davvero, purché sia ​​un'etichetta con una proprietà Text? 2. Se questo è uno dei rari casi in cui hanno davvero un buon motivo per preoccuparsene, chiedi a Intellisense. 3. Se stanno modificando il codice in un IDE senza Intellisense, probabilmente avranno degli inconvenienti molto più grandi di 'var' :)
KutuluMike,

4
Qualcuno con uno scarso senso di astrazione.
Jim Balter,

16

Non ho alcun commento serio sull'operatore ??, poiché non ho mai usato una lingua con un operatore del genere. Per quanto riguarda var, le persone programmano in lingue come Ruby, Python, Perl e PHP che hanno la digitazione completamente implicita in ogni momento. I nativi di queste lingue comprendono che il tipo formale di una variabile è di solito un rumore irrilevante. Sei più interessato a ciò che la variabile può fare , cioè alla sua interfaccia strutturale / anatra.

Allo stesso modo, programma principalmente in D. D è tipicamente statico ma ha la autoparola chiave, che è equivalente a var. È considerato idiomatico usarlo ovunque, a meno che non si veda una necessità specifica di enfatizzare il tipo di qualcosa al lettore o (tramite conversione implicita) al compilatore. Tranne occasionalmente quando usato come tipo di ritorno di funzione (questo è permesso in D), non l'ho mai trovato per ostacolare la leggibilità, perché penso principalmente in termini di interfacce strutturale / anatra, non di tipo formale / nominativo, quando programma.

Inoltre, l'uso IMHO varovunque possibile è un buon esempio di DRY. Il tipo di qualcosa dovrebbe essere specificato in un unico posto, e quindi essere propagato automaticamente ogni volta che deve essere propagato. Se si utilizza vare il tipo formale della variabile deve cambiare ad un certo punto, le modifiche necessarie verranno automaticamente propagate ovunque necessarie dal compilatore, purché il programma sia ancora corretto, anziché che il programmatore debba cambiare manualmente ogni istanza . Questa è una buona cosa (TM).


13

Penso che questa sia una domanda per il team alla fine. Se non è leggibile da nessun altro membro del mio team, non lo userò, anche se potrei provare un paio di volte a convincerli con esempi o sottolineando analoghi abbreviazioni (come + =) che trovano più leggibili.

Tuttavia, se lavoro da solo, allora trovo ?? e var leggibile senza limiti. Anche

var a = b ?? c ?? d ?? e ?? "";

è abbastanza inequivocabile per me.

Gli operatori ternari e dynamicsono una questione diversa, ovviamente.


4
Vorrei usare "String.Empty" qui.
Giobbe

1
@Job, onestamente, anche io. Stavo per inserire qualcosa in quella stringa, quindi non riuscivo a pensare a nulla :)
pdr

4
var a = b ?? c ?? d ?? e ?? String.Empty ?? "";
Lee Louviere,

2
@Xaade Non puoi mai essere abbastanza sicuro. Ma davvero, usare String.Empty o "" è una preferenza personale. Uso "" perché è più corto ...
Carra,

12
@Xaade - se String.Emptymai ritorna null, ci aspetta un sacco di codice rotto.
Jesse C. Slicer,

10

L'argomento dato per l'utilizzo ?? operatore era, toglie la leggibilità nel codice.

Pensandoci brevemente, questo commento mi dice che la persona che ha fatto il commento, non lo capisce bene come dovrebbe. Molto probabilmente è vero in determinate situazioni, ma nel complesso non sconto qualcosa che il team di C # ovviamente ha ritenuto fosse abbastanza importante da aggiungere a causa della "leggibilità". Ho messo questo nella stessa categoria di if(boolean_object)vs if(boolean_object == true). Alcune persone sostengono che il secondo è più leggibile, ma in realtà è solo l'aggiunta di un codice aggiuntivo per qualcuno da leggere / digitare, e in alcune situazioni può essere più confuso (pensa if(boolean_object != false))

La mia domanda è: non succede la stessa cosa quando inizi a usare var?

Il team di C # ti ha permesso di non definire qualcosa che sai come sarà. A meno che non sia assolutamente necessario definire quale sarà una variabile (o è assolutamente importante che un oggetto di ritorno sia di tipo x, o in realtà non sia leggibile), io uso var. var x = "MY_STRING";So che è una stringa osservarla. In verità, non mi interessa davvero che sia una stringa fintanto che fa quello che mi serve per farlo. La definizione del tipo di variabile è a mio vantaggio, non del compilatore. Se qualcosa non va, il compilatore mi dirà quando viene eseguito se ho il tipo di variabile errato.


0

La varparola chiave è, a mio avviso, utilizzata al meglio nelle situazioni per le quali è stata introdotta in origine: query LINQ. In queste query, il tipo del risultato restituito ha spesso un grande nome contorto che è difficile da determinare in anticipo e non aiuta la lettura del lettore su ciò che fa il codice.

Tuttavia, fare var text = "Some text " + variableName + "some more text."è solo pigro.

EDIT: @Jorg Hai saltato su una risposta volutamente semplicistica ma non hai aggiunto nulla alla discussione. OK, che ne dici per un esempio migliore: var items = doc.DocumentElement.FirstChild.ChildNodes;se riesci a capire il tipo da quello ti darò un cookie.


18
Se non riesci a capire che "Some text "è una string, allora hai problemi molto più grandi di cui preoccuparti rispetto al numero di vars nel tuo codice.
Jörg W Mittag,

3
Il problema non lo è var; il problema è il nome variabile "articoli" scadente. Se usi un buon nome di variabile, non c'è niente di sbagliato in var.
Kyralessa,

3
Sto indovinando (senza guardare) che gli elementi sono una raccolta di nodi XML, che mi aspetto di avere tutte le proprietà e i metodi di una raccolta di nodi XML, e questo è davvero tutto ciò che devo sapere.
KutuluMike,

Se hai bisogno di sapere quale tipo rappresenta il var e non puoi dirlo immediatamente guardando, passa il mouse sopra di esso. Non ci vuole molto per capire.
scrwtp

1
"è solo pigro" - Questo non è un argomento contrario. In realtà, non è affatto intelligente.
Jim Balter,

0

Ho un problema fondamentale con l'utilizzo di var.

In questo esempio tutto è affiancato, ma il problema è proprio con soluzioni di grandi dimensioni con librerie o progetti condivisi.

Considera questo:

public MyFirstObject GetMeAnObject() {
    return new MyFirstObject();
}

public void MainProgram() {
    var theObject = GetMeAnObject();
    theObject.PerformOperation();
}

Cosa succede se GetMeAnObject viene modificato, da qualcun altro, per soddisfare le sue esigenze?

public MySecondObject GetMeAnObject() {
    return new MySecondObject();
}

Il metodo MainProgram avrà un grosso errore rosso su .PerformOperation (). Quello che è successo? PerformOperation ha funzionato perfettamente prima. Osserviamo i metodi su theObject ed è semplicemente scomparso senza lasciare traccia. Era lì l'ultima volta e abbiamo bisogno di quel metodo. Potresti passare molto tempo a inseguire la coda e cercare di capire perché, se MyFirstObject ha un metodo chiamato PerformOperation, ora non può essere visto. Tutti "sanno" che GetMeAnObject restituisce un oggetto MyFirstObject, quindi non ha senso verificarlo.

Se avessi digitato esplicitamente theObject, si avrebbe un errore Cast non valido sulla riga che chiama GetMeAnObject e sarebbe ovvio che GetMeAnObject sta restituendo un tipo che non è quello che ti aspetti.

In breve, la dichiarazione esplicita significa che sai cosa significano gli errori. Un cast non valido significa che ti aspettavi un tipo e un altro tipo è stato restituito. Un membro non riconosciuto significa che il membro non è stato riconosciuto.


10
Un collega ha apportato una modifica sostanziale al codice non coperto dai test e pensi che il problema sia var? Non ci si può aspettare che la lingua protegga da quel tipo di comportamento: cosa succede se avessero modificato direttamente MyFirstObject? Si sarebbe comunque rotto, ma nessuna sintassi avrebbe potuto salvarti da quello. Considererei questo anche un punto di forza var: e se invece di restituire MySecondObject ora restituissi invece IMyFirstObject?
Foshi,

2
"Tutti" sanno "che GetMeAnObject restituisce un oggetto MyFirstObject, quindi non ha senso verificarlo." In realtà non riesco a pensare a uno scenario di programmazione in cui dipenderei dalla memoria di ciò che GetMeAnObject se eseguo il debug. Se avessi verificato che PerformOperation non fosse presente, avrei visto il codice e no per un'altra classe. Se in un IDE la classe visualizzasse l'istanza, guardo il tipo di oggetto. In realtà, quando il compilatore mi dice l'errore, direbbe "la classe MySecondObject non ha alcuna operazione PerformOperation". Come è che lo sanno tutti?
Muhammad Alkarouri,
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.