C # sta diventando più difficile da leggere?


15

Con il progredire di C #, sono state aggiunte molte funzionalità linguistiche. È arrivato al punto in cui sta diventando illeggibile per me.

Ad esempio, considera il seguente codice snip dal codice Caliburn.Micro qui :

            container = CompositionHost.Initialize(
                   new AggregateCatalog(
                      AssemblySource.Instance.
                             Select(x => new AssemblyCatalog(x))
                               .OfType<ComposablePartCatalog>()
                )
            );

Ora, questo è solo un piccolo esempio.

Ho una serie di domande:

  • È un problema comune o noto?
  • La comunità C # sta trovando lo stesso?
  • È un problema con la lingua o è lo stile utilizzato dallo sviluppatore?

Esistono soluzioni semplici per comprendere meglio il codice degli altri ed evitare di scrivere codice in questo modo?


6
È la funzione lambda, sono difficili da leggere fino a quando non li capisci davvero.
Ryathal,

9
Penso che non conoscessi davvero la sintassi così come pensavi. Con la pratica leggere il tuo esempio è semplice.
ChaosPandion,

6
@Thomas Owens: Santo merda, almeno dacci un po 'di tempo per modificare le domande per tenerle aperte. 15 minuti? Andiamo ora.
Steven Evers,

4
@DannyVarod: 1. "No" non è una risposta accettabile 2. La domanda è chiusa 3. Se sei d'accordo che la domanda non dovrebbe essere qui, allora contrassegna / vota per chiuderla o modificarla per essere migliore .
Steven Evers,

2
@ Thorbjørn Ravn Andersen - Cosa si può imparare da uno schiaffo? Questo non contiene informazioni!

Risposte:


12

Una breve nota su dove si trova il linguaggio dovrebbe chiarirlo: C # è un linguaggio di programmazione generico ; a differenza di C (come C ++) cerca un'alta astrazione; a differenza dei dialetti Lisp, mira all'espressività pratica e, a differenza di Java, è guidato in modo più aggressivo: Microsoft risponde rapidamente alla domanda.

Questo è il motivo per cui si sta trasformando in una miscela di LINQ, lambda e strane nuove parole chiave: si sta adattando rapidamente ai nuovi domini problematici e questa è in effetti una pendenza scivolosa verso un linguaggio così complesso che pochissimi possono usarlo correttamente (come C ++). Non è un problema con C # stesso, è un problema con qualsiasi lingua con questi obiettivi ambiziosi.

La comunità ne è consapevole e, cosa più importante, i ragazzi dietro C # ne sono profondamente consapevoli (i pochi post di blog e podcast su ciò che c'era dietro le nuove aggiunte in C # 5.0 mostrano quanto questi ragazzi vogliano mantenere le cose semplici). Microsoft sta cercando di togliere parte del carico dalla loro ammiraglia in modo che non diventi un tarpit: l'introduzione del DLR, un riflettore luminoso su nuovi linguaggi (F #).

Inoltre, il materiale didattico su C # (comprese le certificazioni MS) raccomanda stili di utilizzo diversi (ma coerenti) per C # a seconda del problema - scegli la tua arma e attenersi ad essa: LINQ fluente su alcuni problemi, lambda con TPL su altri, semplice -vecchio per la maggior parte.


2
Puoi spiegarci cosa intendi con "a differenza dei dialetti di Lisp punta sull'espressività pratica"?
Giorgio,

27

No. C # ci offre più opzioni per scrivere il codice in modo più succinto. Questo può essere usato o abusato. Se usato correttamente, facilita la lettura del codice. Se usato in modo improprio può rendere più difficile la lettura del codice. Ma i cattivi programmatori hanno sempre avuto la capacità di scrivere codice difficile da leggere.

Facciamo due esempi, entrambi basati su esempi trovati su StackOverflow riguardanti lo stesso problema, trovando tipi con un attributo specifico:

C # 2.0:

static IEnumerable<Type> GetTypesWithAttribute<TAttribute>(bool inherit) 
                              where TAttribute: System.Attribute
{
    foreach(Assembly assembly in AppDomain.Current.GetAssemblies())
    {
        foreach(Type type in assembly.GetTypes()) 
        {
            if (type.IsDefined(typeof(TAttribute),inherit))
                yield return type;
        }
    }
}

C # 4.0:

IEnumerable<Type> GetTypesWith<TAttribute>(bool inherit) 
                              where TAttribute: System.Attribute
{ 
    return from assembly in AppDomain.CurrentDomain.GetAssemblies()
           from type in assembly.GetTypes()
           where type.IsDefined(typeof(TAttribute),inherit)
           select type;
}

IMHO, la nuova sintassi rende molto più facile la lettura.


la nuova sintassi è davvero più facile da leggere, ma più facile da comprendere, come in quello che sta succedendo sotto il cofano? Il primo esempio è comprensibile, il secondo è più leggibile.
nawfal,

4
@nawfal Nella mia esperienza, le persone hanno molte più difficoltà a comprendere i costrutti "return return" che le dichiarazioni linq; quindi direi che il secondo è più leggibile e comprensibile. Nessuno dei due ti dice davvero cosa sta succedendo sotto il cofano, dal momento che entrambi si associano ad astrazioni lontane da come funzionano effettivamente i processori.
Chuu,

Ad essere sincero, non mi piace LINQ perché astrae i loop e incoraggia i programmatori a recuperare i dati in query LINQ separate (con loop separati in background) invece di un loop con un core più complicato.
mg30rg,

8

Quando è stato aggiunto LINQ, ha reso popolare uno stile di codifica che coinvolge molti concatenamenti di metodi fluenti e il passaggio di lambda come parametri.

Questo stile è molto potente quando ti senti a tuo agio. tuttavia si può abusare di rendere il codice abbastanza illeggibile. Non credo che il tuo esempio sia troppo negativo, sebbene il rientro sia un po 'casuale (e questa è una caratteristica comune di questo stile di codice, Visual Studio non lo rientra in modo molto coerente).

Nel mio posto di lavoro, abbiamo discusso di questo stile di codifica durante la revisione dei nostri standard di codifica all'inizio di quest'anno e abbiamo deciso di incoraggiare gli sviluppatori a suddividere il codice in questo modo: in particolare, a non creare e inizializzare oggetti anonimi all'interno di una chiamata di funzione. Quindi il tuo codice diventerebbe:

var assemblyCatalog = AssemblySource.Instance
    .Select(x => new AssemblyCatalog(x))
    .OfType<ComposablePartCatalog>();
var aggregateCatalog = new AggregateCatalog(assemblyCatalog);
container = CompositionHost.Initialize(aggregateCatalog);

1
Non è strano creare un nuovo tipo e poi attivarlo dinamicamente subito dopo?
DeadMG

Probabilmente, ho appena tagliato lo snippet di codice senza alcuna reale considerazione di quale fosse la sua intenzione. Volevo solo dividere tutte le istanze nelle loro righe di codice per mostrare quale effetto avrebbe avuto sull'aspetto del codice.
Carson63000,

Prendo la colpa per il rientro :(). Ecco l'originale: devlicio.us/blogs/rob_eisenberg/archive/2010/07/08/…

1
Sono pienamente d'accordo con questa risposta. Il problema nell'esempio di codice non è la nuova sintassi C #, è che lo scrittore ha cercato di essere intelligente con un codice "one-liner". C'è questa vecchia regola che risale a UNIX: tutto dovrebbe fare solo una cosa e farlo bene. Si applica alla classe, si applica al metodo e, certamente, si applica sicuramente alle righe di codice.
Laurent Bourgault-Roy,

4

Il codice nel tuo esempio non è facilmente leggibile perché

  • Mescola molte nozioni (Composizione, Cataloghi, Aggregati, Assiemi, ComposableParts ...) con diversi livelli di annidamento mentre il codice chiamante dovrebbe in genere avere a che fare con un solo livello. Sembra un po 'una violazione della Legge di Demetra solo con chiamate di metodo nidificate anziché una catena di sotto-proprietà secondarie. Questo confonde in qualche modo l'intenzione dietro la linea di codice.

  • C'è uno strano uso singleton - AssemblySource.Instance.Select()implica che Instance è un IEnumerable, il che è un po 'imbarazzante.

  • La variabile x nell'espressione lambda è brutta. Generalmente provi a dare alle tue variabili lambda l'intenzione di rivelare nomi - aiuta il lettore a identificare di che tipo di dati si tratta la funzione, anche se non ha familiarità con lambdas.

  • Non è chiaro il motivo per cui dovresti filtrare con OfType<T>()una raccolta di oggetti che hai appena rinnovato ...

Tuttavia, tutti questi difetti si riferiscono al modo in cui lo sviluppatore originale ha scritto il codice e alla sua espressività. Questo non è qualcosa di specifico per le ultime versioni di C # e l'aspetto delle espressioni lambda.

Più in generale, aiuta se il lettore del tuo codice sa come funziona lambda, ma con una denominazione abbastanza chiara riesci quasi sempre a rendere il tuo codice leggibile anche a qualcuno con un background pre.NET 3.5.


2

Ogni volta che una nuova versione del linguaggio popolare acquisisce nuovi costrutti, sorgono dibattiti simili.

Ho avuto anche questi dubbi anni fa (http://gsscoder.blogspot.it/2009/08/use-csharps-features-wisely.html).

Secondo me C # si sta evolvendo in modo elegante e coerente.

Il codice nel tuo esempio non è complesso, forse non sei abituato alle espressioni lamda.

Il problema è che C # non è solo un linguaggio orientato agli oggetti, ora supporta anche costrutti funzionali (http://archive.msdn.microsoft.com/FunctionalCSharp/).


1

Mi ci è voluto un po 'di tempo per capire la sintassi di Lambda e vengo da un background di matematica e fisica. È un po 'simile alle espressioni matematiche, anche se usano -> invece di =>:

Esempio matematico f (x): = x-> x + 2, si legge come "La funzione f di x è definita come x mappe su x + 2

c # esempio del myDelegate = x => x +2; questo si legge come "myDelegate è una funzione tale che myDelegate (x) esegue il mapping da x a x + 2

L'incongruenza tra matematica e programmazione non aiuta davvero, anche se suppongo che -> sia già stato ripreso in C ++ come "proprietà di" (urrgghh!)

http://en.wikipedia.org/wiki/List_of_mathematical_symbols


"anche se suppongo che -> fosse già stato ripreso in C ++ come" proprietà di "(urrgghh!)" Come se! Scarsamente in C ++ significa "proprietà dell'allocazione dinamica ...". Se qualcosa non è dinamico usi il punto come in ogni altra lingua.
mg30rg,
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.