Чи стає С # важче читати?


15

Коли C # прогресував, багато мовних функцій було додано. Це дійшло до того, що для мене це стає нечитабельним.

Як приклад, розглянемо наступний фрагмент коду з коду Caliburn.Micro тут :

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

Тепер це лише невеликий приклад.

У мене є ряд питань:

  • Це поширена чи відома проблема?
  • Чи знайде спільнота C # те саме?
  • Це проблема з мовою чи це стиль, який використовує розробник?

Чи є прості рішення, щоб краще зрозуміти код інших та уникати написання коду таким чином?


6
Його лямбда-функція, їх важко читати, поки ви їх справді не отримаєте.
Рятхал

9
Я думаю, ти справді не знав синтаксису так добре, як ти думав. З практикою читання вашого прикладу просто.
ChaosPandion

6
@ Томас Оуенс: Свята людина, принаймні, дай нам трохи часу для редагування питань, щоб вони залишалися відкритими. 15 хвилин? Давай зараз.
Стівен Еверс

4
@DannyVarod: 1. "Ні" не є прийнятною відповіддю 2. Питання закрите 3. Якщо ви погоджуєтесь, що питання не повинно бути тут, прапор / голосування закрити його або відредагувати, щоб краще .
Стівен Еверс

2
@ Thorbjørn Ravn Andersen - Що можна навчитися з ляпаса? Ця інформація не містить!

Відповіді:


12

Швидка примітка про те, де знаходиться мова, має зрозуміти це: C # - мова програмування загального призначення ; на відміну від C (як C ++) він прагне до високої абстракції; На відміну від діалектів Lisp, він спрямований на практичну виразність, і, на відміну від Java, він більш агресивно керований - Microsoft швидко реагує на попит.

Ось чому він перетворюється на суміш LINQ, лямбда та дивних нових ключових слів - він швидко адаптується до нових проблемних доменів, і це справді слизький нахил до мови, такий складний, що дуже мало хто може правильно його використовувати (як C ++). Це не проблема самої C #, це проблема будь-якої мови з цими амбітними цілями.

Спільнота це усвідомлює, і що ще важливіше, хлопці, які стоять за C #, гостро знають про це (кілька записів у блогах та подкастів щодо того, що було за новими доповненнями в C # 5.0, показують, наскільки погано ці хлопці хочуть робити все просто). Microsoft буде намагатися взяти частину навантаження від свого флагманського таким чином, щоб вона не стала тарпіттінга: введення DLR, яскравий прожектор над новими мовами (F #).

Більше того, навчальний матеріал на C # (включаючи сертифікати MS) рекомендує різні (але послідовні) стилі використання для C # залежно від проблеми - виберіть свою зброю та дотримуйтесь її: Вільний LINQ у стилі деяких проблем, лямбда з TPL щодо інших, звичайний -для більшості.


2
Чи можете ви пояснити, що ви маєте на увазі під "діалектами Ліспа, націленими на практичну виразність"?
Джорджіо

27

Ні. C # дає нам більше варіантів, щоб писати код більш лаконічно. Це можна використовувати або зловживати. Якщо правильно використовувати, це полегшує читання коду. При неправильному використанні код може ускладнити читання. Але погані програмісти завжди мали навик писати важко читати код.

Давайте візьмемо два приклади, обидва на основі прикладів, знайдених у StackOverflow щодо тієї самої проблеми, знаходження типів із певним атрибутом:

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, новий синтаксис значно спрощує читання.


новий синтаксис справді легше читати, але простіше зрозуміти, як у тому, що відбувається під кришкою? Перший приклад зрозумілий, другий - більш читабельний.
nawfal

4
@nawfal На моєму досвіді у людей набагато більше проблем з розумінням конструкцій "віддачі", ніж з заявами linq; тому я можу стверджувати, що друге є більш зрозумілим і зрозумілим. Жоден із насправді не каже вам, що відбувається під кришкою, оскільки обидва відображають абстракції далеко не від того, як насправді працюють процесори.
Чуу

Якщо чесно, мені не подобається LINQ, оскільки він абстрагує петлі і закликає кодери отримувати дані в окремих запитах LINQ (з окремими петлями на задньому плані) замість одного циклу зі складнішим ядром.
mg30rg

8

Коли LINQ був доданий, він популяризував стиль кодування, що включає безліч методів ланцюжкового стилю, і передача лямбда в якості параметрів.

Цей стиль дуже потужний, коли вам це зручно. Однак можна зловживати, щоб зробити досить нечитабельний код. Я не думаю, що ваш приклад є занадто поганим, хоча відступ є наче випадковим (і це загальна особливість цього стилю коду, Visual Studio не автоматично відступає від нього).

На моєму робочому місці ми обговорювали цей стиль кодування під час перегляду наших стандартів кодування на початку цього року, і ми вирішили заохотити розробників розбити такий код: конкретно, не створювати та ініціалізувати анонімні об’єкти всередині виклику функції. Таким чином ваш код стане:

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

1
Хіба не дивно створити новий тип, а потім динамічно увімкнути цей тип відразу після цього?
DeadMG

Напевно, я просто нарізав фрагмент коду без будь-якого реального врахування того, який був його намір. Просто хотілося розділити всі інстанції на власні рядки коду, щоб показати, який вплив це матиме на вигляд коду.
Carson63000

Я беру на себе провину за відступ :(). Ось оригінал: devlicio.us/blogs/rob_eisenberg/archive/2010/07/08/…

1
Я повністю згоден з цією відповіддю. Проблема в прикладі фрагмента коду не в новому синтаксисі C #, а в тому, що письменник намагався бути кмітливим з кодом "однолінійний". Існує це старе правило, що починається з UNIX: все повинно робити лише одне , і робити це добре. Він застосовується до класу, він застосовується до методу і, звичайно, найбільш безумовно стосується рядків коду.
Лоран Буро-Рой

4

Код у вашому прикладі не легко читається, оскільки

  • Він змішує багато понять (Склад, Каталоги, Агрегати, Збори, Компонентні Парти ...) з декількома рівнями вкладення, тоді як код виклику, як правило, повинен мати справу лише з одним рівнем. Дещо схоже на порушення Закону Деметера лише за допомогою вкладених методів викликів замість ланцюга суб-суб-властивостей. Це дещо заплутує намір за рядком коду.

  • Існує дивне використання синглтона - AssemblySource.Instance.Select()означає, що Instance - це IEnumerable, що трохи незручно.

  • Змінна x у лямбда-виразі некрасива. Як правило, ви намагаєтеся дати своїм змінним лямбда намір розкривати назви - допомагає читачеві визначити, для якого типу даних йдеться про функцію, навіть якщо він не знайомий з лямбдами.

  • Незрозуміло, чому слід фільтрувати OfType<T>()колекцію предметів, які ви нещодавно створили ...

Однак усі ці недоліки пов'язані з тим, як написав код оригінальний розробник і наскільки виразним він його створив. Це не щось специфічне для останніх версій C # та появи лямбда-виразів.

Загалом, це допомагає, якщо читач вашого коду знає, як працюють лямбда, але при досить чіткому іменуванні вам майже завжди вдається зробити свій код читабельним навіть для когось із фоном pre..NET 3.5.


2

Щоразу, коли нова версія популярної мови набуває нових конструкцій, подібні дебати виникають.

У мене також були такі сумніви років тому (http://gsscoder.blogspot.it/2009/08/use-csharps-features-wisely.html).

На мою думку, C # розвивається елегантно та послідовно.

Код у вашому зразку не складний, можливо, ви не використовуєте ламда-вирази.

Проблема полягає в тому, що C # - це не лише об'єктно-орієнтована мова, вона тепер підтримує також функціональні конструкції (http://archive.msdn.microsoft.com/FunctionalCSharp/).


1

Щоб зрозуміти синтаксис Лембда, мені знадобилося трохи часу, і я з математики та фізики. Це трохи схоже на математичні вирази, що б вони не використовували -> замість =>:

Приклад математики f (x): = x-> x + 2, це означає: "Функція f of x визначається як x відображається на x + 2

c # приклад del myDelegate = x => x +2; це звучить як "myDelegate - така функція, що myDelegate (x) відображає х на x + 2

Невідповідність між математикою та програмуванням насправді не допомагає, хоча я гадаю -> вже сприймався в C ++ як "властивість" (urrgghh!)

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


"хоча я гадаю -> вже було сприйнято в C ++ як" властивість "(urrgghh!)" Ніби! Погано в C ++ це означає "властивість динамічно виділеного ...". Якщо щось не динамічне, ви користуєтеся періодом, як і в будь-якій іншій мові.
mg30rg
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.