Запутанный код C # - PullRequest
       18

Запутанный код C #

5 голосов
/ 24 января 2010

Несколько лет назад они были соревнованием, чтобы увидеть, кто может создать самый запутанный код C, и некоторые результаты были совершенно нечитаемыми. С было так. В частности, вы можете все испортить, особенно с препроцессором.

Однако многие из новых функций C # предлагают удивительную возможность запутать код. Мне было интересно, есть ли у кого-нибудь мнение о том, как найти правильный баланс между краткостью и ясностью кода. Позвольте мне предложить один пример для обсуждения - задачу заполнения элементов в ListView. (Да, я знаю, что вы можете сделать это с привязкой данных, но идите со мной здесь.)

Элемент управления состоит из двух столбцов, которые должны быть заполнены массивом структура Person { публичное имя строки; публичный строковый адрес; }; * +1005 *

Один, ясный и простой способ заключается в следующем:

private void Fill(Person[] people)
{
    foreach(Person person in people)
    {
        string[] columns = new string[2];
        columns[0] = person.name;
        columns[1] = person.address;            
        ListViewItem item = new ListViewItem(columns);
        listView1.items.Add(item);
    }
}

Ясно и просто для понимания.

Я также мог бы написать это так:

private void Fill(Person[] people)
{
    foreach(Person person in people)
    {
        string[] columns = new string[] { person.name, person.address };
        ListViewItem item = new ListViewItem(columns);
        listView1.items.Add(item);
    }
}

или даже:

private void Fill(Person[] people)
{
    foreach(var person in people) // Note use implicit typing here
    {
        listView1.items.Add(new ListViewItem(
        new string[] { person.name, person.address }));
    }
}

Наконец, я мог бы написать это так:

private void Fill(Person[] people)
{
    Array.ForEach(people, item =>
    listView1.items.Add(new ListViewItem(
    new string[] { person.name, person.address}));
}

Каждый использует различные новые функции языка в большей или меньшей степени. Как вы находите баланс между краткостью и ясностью? Должны ли мы проводить ежегодный конкурс «Обфусцированный С #»?

Ответы [ 6 ]

24 голосов
/ 24 января 2010

Знаешь что сложно? Написание кода, который другие могут читать и поддерживать. Любой идиот может написать код, который компилируется и его невозможно поддерживать.

Всегда поддерживает ремонтопригодность: вот как вы находите баланс.

Edit:

«Любой дурак может написать код, понятный компьютеру. Хорошие программисты пишут код, понятный людям».

  • Мартин Фаулер, Рефакторинг: улучшение дизайна существующего кода

Спасибо roygbiv за поиск вышеуказанной цитаты. Извинения Фаулеру за убийство его цитаты; Я знал, что прочитал это раньше, я просто не мог вспомнить, где.

6 голосов
/ 24 января 2010

Сложение всего в одну строку не делает его "запутанным" - оно просто заставляет вас многократно прокручивать. Любой, кто знает C #, понимает любой из приведенных вами примеров, и если бы вы использовали переносы строк, то ни один из них не был бы намного лучше или хуже других.

2 голосов
/ 24 января 2010

Код для максимальной читабельности, , но :

  1. Помните, что излишняя многословность и синтаксический шум ухудшают читабельность. Большая краткость может совпадать с улучшенной читабельностью, если более краткая запись позволяет вам выразить свое намерение более прямо. Например, сравните реальные лямбда-функции с имитацией их с помощью однопроцессных интерфейсов.

  2. Предположим, что другие люди, которые читают ваш код, являются приличными программистами и знают язык, на котором вы работаете. Не допускайте уровня знаний юриста по языку, но приобретайте хорошие рабочие знания. Не кодируйте с наименьшим общим знаменателем, потому что, хотя он может сделать ваш код более понятным для обезьян, он будет раздражать вас и программистов, которые на самом деле знают, что они делают.

Более конкретно, в примере 1 слишком много синтаксического шума для чего-то такого простого. Пример 4 очень трудно разобрать человеку. Я бы сказал, что 2 и 3 довольно хороши, хотя в случае примера 3 я бы немного переформатировал его, просто чтобы человеку было проще разобрать все вложения вызова функции:

private void Fill(Person[] people)
{
    foreach(var person in people)
    {
        listView1.items.Add(
            new ListViewItem(
                new string[] { person.name, person.address }
            )
         );
    }
}

Теперь у вас есть лучшее из обоих миров: он может быть легко проанализирован людьми и не имеет никаких лишних, излишне подробных временных переменных.

Редактировать: Я также думаю, что использование неявной типизации переменных, то есть var в большинстве случаев вполне нормально. Люди пишут отлично читаемый код на динамических языках, где неявная типизация является единственным видом типизации, и большую часть времени формальные типы ваших переменных представляют собой детали низкого уровня, которые не имеют ничего общего с намерениями высокого уровня вашего кода.

1 голос
/ 24 января 2010

C # и языки VB.NET были разработаны для большей ясности, потому что они работают на более высоком уровне, чем C. C программирует, так сказать, по-металлически. Невозможно по своему замыслу написать запутанный C # как у C.

«Любой дурак может написать код, понятный компьютеру. Хорошие программисты пишут код, понятный людям».

  • Мартин Фаулер, Рефакторинг: улучшение дизайна существующего кода
1 голос
/ 24 января 2010

По крайней мере, в отношении примера, который вы приводите здесь, я не думаю, что запутанность возрастает, пока вы продолжаете, пока не дойдете до последнего. Даже там, единственная причина для любой двусмысленности - присутствие Лямбды, и это только требует некоторого привыкания. Таким образом, у новичка могут возникнуть проблемы с последним, но он не должен находить другие нечитаемыми, так как старые записи о диких соревнованиях C были нечитаемыми.

Разница в том, что все эти примеры на C # находятся на одном уровне абстракции - более лаконичные примеры просто удаляют "пух". В C у вас есть возможность для неоднозначности из-за A) произвольно переименованных / псевдонимов конструкций и B) нескольких уровней доступа к памяти, объединенных в один оператор.

Итак, вы можете исправить неясный код на ЛЮБОМ языке, но я не думаю, что C # склонен к нему, как C, и, на самом деле, я думаю, что это более понятный язык, чем многие, даже когда используется более продвинутые конструкции.

0 голосов
/ 28 ноября 2012

Я не нахожу пример запутанным.

Во-первых, намерение настолько болезненно ясно, что новичок более вероятно узнает, что делает лямбда, чем не понимает код. Это идеальное место для использования более «продвинутых» техник, когда даже тот, кто не имеет понятия, что он делает, понимает, что он «должен» делать.

Во-вторых, все вышеперечисленное не только не запутано, но и является совершенно идиоматическим C #. Последнее, вероятно, не так много из-за не столь широкого использования Array.ForEach, с которым большинство людей (с которыми я работал) будет использовать LINQ.

...