Более свободно C # / .NET - PullRequest
       59

Более свободно C # / .NET

15 голосов
/ 16 декабря 2009

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

Общие мысли, пожалуйста. Другие методы расширения, которые могут быть добавлены?

var ddl = Page.FindControl("LocationDropDownList") as DropDownList;

ddl.Visible = true;
ddl.SelectedValue = "123";

if(isAdmin)
    ddl  .SelectedValue = "111";

становится:

Page.FindControl("LocationDropDownList")
    .CastAs<DropDownList>()
    .With(d => d.Visible = true)
    .With(d => d.SelectedValue = "123")
    .WithIf(isAdmin, d => d.Items.Add(new ListItem("Admin", "1")));

Или:

 Page.FindControl("LocationDropDownList")
       .CastAs<DropDownList>()
       .With(d =>
       {
           d.Visible = true;
           d.SelectedValue = "123";
       })
       .WithIf(isAdmin, d => d.SelectedValue = "111");

Методы расширения:

public static TResult CastAs<TResult>(this object obj) where TResult : class
{
    return obj as TResult;
}

public static T With<T>(this T t, Action<T> action)
{
    if (action == null)
        throw new ArgumentNullException("action");

    action(t);

    return t;
}

public static T WithIf<T>(this T t, bool condition, Action<T> action)
{
    if (action == null)
        throw new ArgumentNullException("action");

    if (condition)
        action(t);

    return t;
}

Ответы [ 21 ]

60 голосов
/ 16 декабря 2009

Среди моих практических правил для написания понятного кода: помещать все побочные эффекты в заявления; выражения без утверждений не должны иметь побочных эффектов.

Ваша первая версия программы четко следует этому правилу. Вторая версия явно нарушает его.

Еще одна мысль: если бы я читал код, подобный тому, который вы отображали, я, естественно, предположил бы, что целью кода было создать лениво вычисленную структуру, которая представляла бы эти операции - именно поэтому понимание запросов в C # 3 строится таким образом. Результатом выражения запроса является объект, представляющий отложенное применение запроса.

Если ваше намерение состоит в том, чтобы охватить понятие «выполнить эти побочные эффекты отложенным способом в более поздний момент моего выбора», то это разумный подход. По сути, то, что вы строите, - это монада с побочными эффектами. Если ваше намерение состоит в том, чтобы просто предоставить другой синтаксис для быстро исполняемого кода, то это просто запутанно, многословно и не нужно.

49 голосов
/ 16 декабря 2009

Я не вижу в этом никакого преимущества, кроме как сбить с толку читателя. Что касается моего коллеги-ответчика, я хотел бы знать, на какой планете это более читабельно. Насколько я могу судить, первая версия обладает более или менее совершенной читабельностью, тогда как она довольно читабельна, но заставляет читателя задуматься о том, происходит ли какая-то странная магия внутри With и WithIf.

По сравнению с первой версией он длиннее, его труднее набрать, он менее очевиден и менее производителен.

11 голосов
/ 16 декабря 2009

Полагаю, я не вижу, что получат новые версии. Оригинал довольно ясный и менее многословный. Я думаю, что это будет быстрее. Я бы не стал использовать (злоупотреблять?) Такие языковые функции, если бы не было явной выгоды.

9 голосов
/ 16 декабря 2009

Еще один голос за "не полезно". Метод расширения With ничего не делает, кроме как заключает в последовательность последовательные операторы с помощью метода. C # уже имеет встроенную функцию для операторов последовательности, которая называется ;.

Аналогично, WithIf переносит оператор if без каких-либо изменений в потоке управления. С моей точки зрения, вы приглашаете только такие методы, как:

public static T For<T>(
    this T t, int start, Func<int, bool> cond, Action<T, int> f)
{
    for(int i = start; cond(i); i++)
    {
        f(t, i);
    }
    return t;
}
6 голосов
/ 16 декабря 2009

Оригинал более читабельный.

Самым простым изменением API было бы сделать объект, возвращаемый FindControl (), в стиле Builder (где все методы набора возвращают 'this'):

Page.FindControl("LocationDropDownList")
    .setVisible(true)
    .setSelectedValue(isAdmin ? "111" : "123");
5 голосов
/ 16 декабря 2009

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

4 голосов
/ 16 декабря 2009

Это злоупотребление методом расширения, если я его когда-либо видел!

4 голосов
/ 16 декабря 2009

Мне удобнее с первой версией. Это займет меньше времени, чтобы прочитать и понять. Я согласен, что методы расширения также хороши, если вы знакомы с ним и знакомы с методом With, но в чем его преимущество в этом случае?

4 голосов
/ 16 декабря 2009

Это просто разные стили кодирования, что вы подразумеваете под "слишком большим уходом"? Отправление от чего? К чему ты привык? Только вы можете решить это. Я скажу, что With блок VB принес больше вреда, чем пользы для читабельности кода, и я не буду пытаться копировать поведение в C #, но это всего лишь мое предпочтение.

Я почти всегда использую это для FindControl (да, строго набрал RepeaterItem, это не обязательно, но это единственное, что я когда-либо использовал для этого):

public static T FindControl<T>(this RepeaterItem item, string id) 
{
    return item.FindControl(id) as T;
}

И вызывать это так:

Literal myLiteral = e.Item.FindControl<Literal>("myLiteral");
3 голосов
/ 16 декабря 2009

Если это была язык функция:

With(Page.FindControl("LocationDropDownList") as DropDownList)
{
    Visible = true;
    SelectedValue = "123";
    if(isAdmin)    
      Add(new ListItem( "111"));
}

Вы бы выиграли что-то:

  • избегать избыточности мутированного объекта
  • все языковые функции, доступные в блоке «С»

Выше пытается подражать стилю, не пожиная выгоды. Грузовой культ .

(Примечание: я понимаю различные аргументы против этого, но все равно было бы неплохо)


Кстати, некоторые из моих помощников C32 Win32 UI содержат сеттеры, которые используют цепочку, аналогичную той, которую вы хотите достичь:

LVItem (m_lc, idx) .SetText (_T ("Hello")). SetImg (12) .SetLParam (id);

В этом случае я меньше всего выигрываю «без избыточности», но это потому, что у меня нет свойств.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...