Il nuovo operatore null-condizionale di C # 6.0 va contro la Legge di Demetra?


29

La legge di Demetra afferma quanto segue:

  • Ogni unità dovrebbe avere una conoscenza limitata delle altre unità: solo le unità "strettamente" correlate all'unità corrente.
  • Ogni unità dovrebbe parlare solo con i suoi amici; non parlare con estranei.
  • Parla solo con i tuoi amici immediati.

C # 6.0 ha introdotto un nuovo operatore chiamato operatore null-condizionale . IMHO, semplifica la codifica e migliora la leggibilità. Ma semplifica anche la scrittura di più codice accoppiato, poiché è più semplice navigare nei campi di classe, verificando già la nullità (qualcosa del genere var x = A?.B?.C?.D?.E?.F?).

È corretto affermare che questo nuovo operatore è contrario alla Legge di Demetra?


2
Perché credi che A?.B?.C?.D?.E?.F?lo violerebbe? LoD non riguarda il numero di punti e se il metodo di chiamata ha tali informazioni sulla struttura che non viola i suoi punti, una chiamata del genere sarebbe perfettamente accettabile. Che tale codice potrebbe violare LoD non è sufficiente per dire che tutti gli usi di esso fare violano LoD.

14
Leggendo " La legge di Demetra non è un esercizio di conteggio dei punti "? Discute questo esempio esatto.
uscita il

@outis: lettura eccellente. Non sto dicendo che ogni codice in forma di X.Y.Z.W.Usia una violazione della "legge". Ma, nella mia esperienza con il codice, il 90% delle volte è semplicemente un brutto codice accoppiato.
Arthur Rizzo,

2
@ArthurRizzo ma questo non è un problema con l'operatore condizionale null che va contro LoD. Questo è il codice che è in errore. L'operatore è solo uno strumento per semplificare la lettura umana. Il .?non viola più LoD di +o -non lo fa.

1
RC Martin distingue tra classi di dati puri e classi comportamentali. Se le Proprietà a cui si accede espongono i dati interni di una classe comportamentale, lo snippet viola sicuramente il LoD, ma ciò non ha nulla a che fare con l'operatore nullo-condizionale. In ogni caso, le proprietà non sono destinate a esporre dati interni, che potrebbero essere un odore, ma non violano il LoD. Secondo RC Martin lo schema potrebbe essere assolutamente valido con classi di dati puri.
Paul Kertscher,

Risposte:


44

È corretto affermare che questo nuovo operatore è contrario alla Legge di Demetra?

No *


* L'operatore condizionale null è uno strumento all'interno del linguaggio e del framework .NET. Qualsiasi strumento ha la capacità di essere abusato e utilizzato in modi che potrebbero danneggiare la manutenibilità di una determinata applicazione.

Ma il fatto che uno strumento possa essere abusato non significa necessariamente che debba essere abusato, né che lo strumento violi determinati principi che possono essere sostenuti.

La Legge di Demetra e altri sono linee guida su come dovresti scrivere il tuo codice. È mirato agli umani, non agli strumenti. Quindi il fatto che il linguaggio C # 6.0 abbia un nuovo strumento al suo interno non influenza necessariamente il modo in cui dovresti scrivere e strutturare il tuo codice.

Con qualsiasi nuovo strumento, è necessario valutare come ... se il ragazzo che finisce per mantenere il vostro codice sarà uno psicopatico violento ... . Nota di nuovo che questa è una guida per la persona che scrive il codice e non sugli strumenti utilizzati.


foo = new FiveDMatrix(); foo.get(0).get(0).get(0).get(0).set(0,1);andrebbe bene (e non peggio di foo[0][0][0][0][0] = 1) ... e molte altre situazioni in cui tale non viola il LoD.

@MichaelT Quando inizi ad entrare nelle matrici di quella dimensionalità, sembra che sarebbe più facile trattare gli indici come un vettore / tupla / matrice stessa e lasciare che gli interni della classe matrice si preoccupino di come i dati vengono effettivamente archiviati. (Che, ora che ci penso, è un'applicazione della Legge di Demetra, almeno per quanto riguarda l'incapsulamento.)
JAB

(E, naturalmente, questo tipo di pratica semplifica l'implementazione del slicing multidimensionale e ha alcuni strumenti a matrice davvero potenti.)
JAB

1
@JAB Stavo solo cercando di fare un esempio. Probabilmente uno migliore sarebbe Dom file = prase("some.xml"); file.get(tag1).getChild().get(tag2).getChild() ...: è un problema di elaborazione della struttura di un codice stupido. Non è uno sconosciuto ... è solo stupido. Il .?diventa molto utile in tali strutture.

10

Una specie di.

Se stai effettuando un solo accesso ( a?.Foo), equivale a:

a == null ? null : a.Foo

che la maggior parte delle persone concorderebbe non è una violazione della Legge di Demetra. A quel punto, è solo zucchero sintattico a migliorare la leggibilità.

Nulla di più di questo, e probabilmente violerebbe la Legge di Demetra, e questa caratteristica tende a promuovere quel tipo di utilizzo. Direi anche che il solo "buon" utilizzo da solo non è sufficiente a giustificare questo tipo di modifica della lingua, quindi mi aspetto che sia stato realizzato per supportare un uso meno chiaramente buono.

Detto questo, vale la pena ricordare che la Legge di Demetra non è una legge in sé, ma più una linea guida. Un sacco di codice lo viola e funziona bene. A volte la semplicità del design o del codice vale più del rischio rappresentato dalla violazione della Legge di Demetra.


nient'altro che non rompe necessariamente il LoD, ad esempio il modello del costruttore
jk.

@Telastyn: La nuova sintassi del linguaggio di cui stiamo parlando non chiamate di metodo di supporto: a?.Func1(x)?.Func2(y) L'operatore nulla coalescenza è un'altra cosa.
Ben Voigt,

@BenVoigt - ah, stavo uscendo dall'articolo, che indicava che funzionava solo con campi, proprietà e indicizzatori. Non avevo a portata di mano MSVS2015 con cui provare. Hai ragione.
Telastyn,

1
a? .Foo non è del tutto equivalente a a == null? null: a. Foo. Il primo valuta una sola volta, il secondo la valuta due volte. Ciò potrebbe importare se un fosse un iteratore.
Loren Pechtel,

9

No. Consideriamo sia l'operatore da solo, sia l'uso pesantemente incatenato che hai per esso.

Da solo .?Adipende dalla stessa quantità di conoscenza della classe del valore di sinistra e del tipo restituito dal metodo .A != null, vale a dire, vale a dire. Deve sapere che la Aproprietà esiste e restituisce un valore che può essere confrontato null.

Possiamo solo sostenere che ciò viola la legge di Demetra se le proprietà digitate lo fanno. Non siamo nemmeno costretti ad avere Acome tipo concreto (il suo valore potrebbe essere di tipo derivato). L'accoppiamento qui è minimo.

Adesso consideriamo var x = A?.B?.C?.D?.E?.F.

Il che significa che Adeve essere di un tipo che potrebbe essere nullo o potrebbe avere una Bproprietà, che deve essere di un tipo che potrebbe essere nullo o avere una Cproprietà, e così via fino a quando il tipo di Eproprietà è qualcosa che potrebbe essere nullo o potrebbe avere una Fproprietà.

In altre parole, dobbiamo farlo con una lingua tipizzata staticamente o aver applicato un vincolo sui tipi che possono essere restituiti se la digitazione è libera. C # nella maggior parte dei casi usa la tipizzazione statica, quindi non abbiamo cambiato nulla.

Se avessimo quindi il seguente codice violerebbe anche la legge:

ExplicitType x;
var b = A.B;
if (b == null)
  x = null;
else
{
  var c = b.C;
  if (c == null)
    x = null;
  else
  {
    var d = c.D;
    if (d == null)
      x = null;
    else
    {
      var e = d.E;
      if (e == null)
        x = null;
      else
        x = e.F;
    }
  }
}

Che è esattamente lo stesso . Questo codice che utilizza l'accoppiamento di diversi elementi deve "conoscere" l'intera catena di accoppiamento, ma utilizza un codice che non viola la Legge di Demetra per farlo, con ogni unità che ha un accoppiamento ben definito con il prossimo.


3
+1 il nuovo operatore è semplicemente zucchero sintattico per la ricetta amara che hai descritto.
Ross Patterson,

1
Bene, se uno sviluppatore scrive un codice simile a quello penso che sia più facile notare che qualcosa potrebbe non essere giusto. So che l'operatore è lo zucchero sintetico al 100%, ma comunque, penso che le persone tendano a sentirsi più a proprio agio scrivendo qualcosa di simile var x = A?.B?.C?.D?.E?.Fa tutti quegli if / elses anche se alla fine sono uguali.
Arthur Rizzo,

2
È più facile notare che qualcosa non va A?.B?.C?.D?.E?.Fperché c'è meno che può essere sbagliato; o dovremmo cercare di passare Fattraverso quel percorso, oppure non dovremmo, mentre la forma più lunga potrebbe contenere errori al suo interno e l'errore di non essere la cosa giusta da fare.
Jon Hanna,

@ArthurRizzo Ma se associ il suddetto tipo di codice alle violazioni dei LoD, allora è facile perderli nel caso in cui non sia necessario un controllo nullo e puoi semplicemente farlo A.B.C.D. È molto più semplice avere una sola cosa da cercare (accesso alla proprietà concatenato) piuttosto che due cose diverse che dipendono da un dettaglio piuttosto irrilevante (controllo null)
Ben Aaronson,

5

L'oggetto può essere creato allo scopo di incapsulare comportamenti o conservare dati, e gli oggetti possono essere creati allo scopo di essere condivisi con codice esterno o tenuti in privato dal loro creatore.

Gli oggetti creati allo scopo di incapsulare comportamenti (condivisi o meno) o per essere condivisi con codice esterno (sia che incapsulino comportamenti o dati) dovrebbero essere generalmente accessibili attraverso la loro interfaccia di superficie. Quando gli oggetti che contengono dati vengono creati per essere utilizzati esclusivamente dal loro creatore, tuttavia, non si applicano le normali ragioni della Legge della Demetra per evitare l'accesso "profondo". Se parte di una classe che archivia o manipola i dati nell'oggetto viene modificata in un modo che richiederebbe la regolazione di altro codice, sarà possibile garantire che tutto tale codice venga aggiornato perché - come notato sopra - l'oggetto è stato creato per l'uso esclusivo di una classe.

Mentre penso al? l'operatore avrebbe potuto essere progettato meglio, ci sono abbastanza situazioni in cui gli oggetti fanno uso di strutture di dati nidificati che l'operatore ha molti casi d'uso che non violerebbero i principi espressi dalla Legge di Demetra. Il fatto che possa essere utilizzato per violare il LoD non dovrebbe essere considerato un argomento contro l'operatore, poiché non è peggio del "." operatore al riguardo.


Perché la Legge di Demetra non si applica agli oggetti contenenti dati?
Telastyn,

2
@Telastyn: lo scopo del LoD è quello di evitare problemi che possono sorgere se un pezzo di codice accede a oggetti interni che qualcos'altro potrebbe manipolare o curare . Se nient'altro nell'universo potrebbe manipolare o preoccuparsi dello stato degli oggetti interni, allora non è necessario proteggersi da tali problemi.
supercat,

Non sono sicuro di essere d'accordo. Non è che altre cose possano interessare di modificare i dati, è che stai accoppiando l'oggetto contenuto tramite un percorso (essenzialmente tre punti di accoppiamento: i due oggetti e la loro relazione). A volte quell'accoppiamento non sarà un grosso problema, ma mi sembra ancora maleodorante.
Telastyn,

@Telastyn: il tuo punto sui percorsi è buono, ma penso che il mio punto sia valido. L'accesso a un oggetto tramite più percorsi crea un accoppiamento tra tali percorsi. Se un certo accesso avviene tramite un percorso poco profondo, anche l'accesso tramite un percorso profondo può causare accoppiamenti indesiderati. Se tutti gli accessi avvengono attraverso un particolare percorso profondo, tuttavia, non ci sarà nulla per cui quel percorso profondo si accoppi.
supercat,

@Telastyn Va benissimo attraversare una struttura di dati per arrivare ai dati in profondità. Non è uguale alle chiamate di metodo nidificate. A volte ti viene richiesto di conoscere una struttura di dati e come è nidificata, lo stesso non vale per oggetti come un servizio e i suoi servizi / repository nidificati, ecc.
Per Hornshøj-Schierbeck
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.