W miarę postępu C # dodano wiele funkcji językowych. Doszło do tego, że stało się dla mnie nieczytelne.
Jako przykład rozważ następujący fragment kodu z kodu Caliburn.Micro tutaj :
container = CompositionHost.Initialize(
new AggregateCatalog(
AssemblySource.Instance.
Select(x => new AssemblyCatalog(x))
.OfType<ComposablePartCatalog>()
)
);
To tylko mały przykład.
Mam kilka pytań:
- Czy to powszechny czy znany problem?
- Czy społeczność C # znajduje to samo?
- Czy to jest problem z językiem, czy to styl używany przez programistę?
Czy są jakieś proste rozwiązania pozwalające lepiej zrozumieć kod innych użytkowników i uniknąć pisania kodu w ten sposób?
c#
readability
Steven Evers
źródło
źródło
Odpowiedzi:
Szybka uwaga na temat tego, gdzie jest język, powinna to wyjaśnić: C # jest językiem programowania ogólnego przeznaczenia ; w przeciwieństwie do C (jak C ++) dąży do wysokiej abstrakcji; w przeciwieństwie do dialektów Lisp ma praktyczną ekspresję, a w przeciwieństwie do Javy jest bardziej agresywnie napędzany - Microsoft szybko reaguje na popyt.
Właśnie dlatego zamienia się w mieszankę LINQ, lambd i dziwnych nowych słów kluczowych - szybko dostosowuje się do nowych domen problemowych i jest to rzeczywiście śliskie nachylenie w kierunku języka tak złożonego, że tylko nieliczni potrafią go poprawnie używać (jak C ++). To nie jest problem z samym C #, to problem z dowolnym językiem z tymi ambitnymi celami.
Społeczność zdaje sobie z tego sprawę, a co ważniejsze, osoby stojące za C # są tego w pełni świadome (kilka wpisów na blogu i podcastów na temat tego, co było za nowymi dodatkami w C # 5.0, pokazuje, jak źle ci faceci chcą uprościć sprawę). Microsoft jest próbuje przejąć część obciążenia od ich flagowego taki sposób, że nie stanie się Tarpit: wprowadzenie DLR, jasnym świetle reflektorów na nowe języki (F #).
Co więcej, materiały szkoleniowe na temat C # (w tym certyfikaty MS) zalecają różne (ale spójne) style użycia C # w zależności od problemu - wybierz broń i trzymaj się tego: płynne LINQ w przypadku niektórych problemów, lambdas z TPL w innych, zwykły - stary dla większości.
źródło
Nie. C # daje nam więcej możliwości bardziej zwięzłego pisania kodu. Można to wykorzystać lub wykorzystać. Prawidłowe użycie sprawia, że kod jest łatwiejszy do odczytania. Niewłaściwe użycie może utrudnić odczytanie kodu. Ale źli programiści zawsze mieli umiejętność pisania trudnego do odczytania kodu.
Weźmy dwa przykłady, oba w oparciu o przykłady znalezione w StackOverflow dotyczące tego samego problemu, znajdując typy o określonym atrybucie:
C # 2.0:
C # 4.0:
IMHO, nowa składnia znacznie ułatwia czytanie.
źródło
Kiedy dodano LINQ, spopularyzował on styl kodowania obejmujący wiele metod łączenia w stylu Fluent i przekazywanie lambdów jako parametrów.
Ten styl jest bardzo mocny, gdy czujesz się dobrze. Jednak może to być nadużywane do kodu dość nieczytelny. Nie sądzę, aby twój przykład był taki zły, chociaż wcięcie jest trochę losowe (i jest to wspólna cecha tego stylu kodu, Visual Studio nie wcina go zbyt konsekwentnie).
W moim miejscu pracy omawialiśmy ten styl kodowania podczas przeglądu naszych standardów kodowania na początku tego roku i postanowiliśmy zachęcić deweloperów do zerwania takiego kodu: w szczególności, aby nie tworzyć ani inicjować anonimowych obiektów wewnątrz wywołania funkcji. Twój kod stałby się:
źródło
Kod w twoim przykładzie nie jest łatwy do odczytania, ponieważ
Łączy wiele pojęć (Kompozycja, Katalogi, Agregaty, Złożenia, Części Composable ...) z kilkoma poziomami zagnieżdżania, podczas gdy kod wywołujący powinien zazwyczaj zajmować się tylko jednym poziomem. Wygląda trochę jak naruszenie Prawa Demetera tylko w przypadku zagnieżdżonych wywołań metod zamiast łańcucha podrzędnych właściwości. To nieco zaburza intencje stojące za linią kodu.
Dziwne jest użycie singletonu -
AssemblySource.Instance.Select()
oznacza to, że Instancja jest IEnumerable, co jest nieco niezręczne.Zmienna x w wyrażeniu lambda jest brzydka. Zasadniczo próbujesz nadać swoim zmiennym lambda intencje ujawniające nazwy - pomaga czytelnikowi określić, jakiego rodzaju danych dotyczy ta funkcja, nawet jeśli nie zna lambdas.
Nie jest jasne, dlaczego należy filtrować za
OfType<T>()
pomocą kolekcji obiektów, które właśnie odkryłeś ...Jednak wszystkie te wady dotyczą sposobu, w jaki pierwotny programista napisał kod i tego, jak wyrazisty go zaprojektował. Nie jest to coś specyficznego dla najnowszych wersji C # i wyglądu wyrażeń lambda.
Mówiąc bardziej ogólnie, pomaga to, jeśli czytelnik twojego kodu wie, jak działają lambdas, ale przy wystarczająco jasnym nazewnictwie prawie zawsze udaje ci się sprawić, że kod jest czytelny nawet dla osób z wcześniejszym niż .NET 3.5.
źródło
Za każdym razem, gdy nowa wersja popularnego języka zyskuje nowe konstrukcje, pojawiają się podobne debaty.
Miałem te wątpliwości także wiele lat temu (http://gsscoder.blogspot.it/2009/08/use-csharps-features-wisely.html).
Moim zdaniem C # ewoluuje w elegancki i konsekwentny sposób.
Kod w twojej próbce nie jest złożony, być może nie używasz wyrażeń lamda.
Problem polega na tym, że C # to nie tylko język zorientowany obiektowo, ale obsługuje również konstrukcje funkcjonalne (http://archive.msdn.microsoft.com/FunctionalCSharp/).
źródło
Trochę czasu zajęło mi zrozumienie składni Lambda, a ja jestem z matematyki i fizyki. Jest trochę podobny do wyrażeń matematycznych, mimo że używają -> zamiast =>:
Przykład matematyki f (x): = x-> x + 2 oznacza to, że „Funkcja f of x jest zdefiniowana jako x map na x + 2
c # przykład del myDelegate = x => x +2; to brzmi „myDelegate to funkcja taka, że myDelegate (x) mapuje x na x + 2
Niespójność między matematyką a programowaniem tak naprawdę nie pomaga, chociaż przypuszczam, że -> zostało już uwzględnione w C ++ jako „właściwość” (urrgghh!)
http://en.wikipedia.org/wiki/List_of_mathematical_symbols
źródło