Более свободно С#/.NET
Один из моих коллег придумал это, и мне интересно, что другие думают? Лично мне интересно, интересно ли это слишком большой отъезд? Примеры кода ниже. Методы расширения внизу.
Общие мысли, пожалуйста. Другие методы расширения, которые можно добавить?
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;
}
Ответы
Ответ 1
Среди моих правил для написания четкого кода: поместить все побочные эффекты в утверждения; выражения без выражения не должны иметь побочных эффектов.
Ваша первая версия программы четко следует этому правилу. Вторая версия явно нарушает его.
Дополнительная мысль: если бы я читал код, как код, который вы отображали, я бы, естественно, предположил, что цель кода заключалась в создании лениво-оцененной структуры, которая представляла эти операции - именно поэтому Таким образом, построены запросы на С# 3. Результатом выражения запроса является объект, представляющий отложенное приложение запроса.
Если ваше намерение состоит в том, чтобы зафиксировать понятие "выполнить эти побочные эффекты отложенным образом в более поздний момент моего выбора", тогда это разумный подход. По существу то, что вы создаете, является монадой, создающей побочные эффекты. Если ваше намерение состоит лишь в том, чтобы предоставить другой синтаксис для нетерпеливо исполняемого кода, тогда это просто путано, многословно и ненужно.
Ответ 2
Я не вижу никакого преимущества для этого, кроме того, что вы сбиваете с толку читателя. Что касается моего коллеги-ответчика, я хотел бы узнать, на какой планете это более читаемо. Насколько я могу судить, первая версия имеет более или менее совершенную читаемость, тогда как это достаточно читаемо, но заставляет читателя задаться вопросом, есть ли какая-то странная магия в With
и WithIf
.
По сравнению с первой версией это длиннее, сложнее вводить, менее очевидно и менее результативно.
Ответ 3
Наверное, я не понимаю, какие новые версии вы получите. Оригинал довольно ясный и менее многословный. Я бы предположил, что это будет быстрее. Я бы избегал использовать (злоупотреблять?) Языковые функции, подобные этому, если нет явной выгоды.
Ответ 4
Еще одно голосование за "не полезно". Метод расширения With
не делает ничего, кроме того, что он завершает упорядоченные инструкции с помощью метода. С# уже имеет встроенную функцию для операторов последовательности, называемую ;
.
Аналогично, 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;
}
Ответ 5
Оригинал более читабельен.
Простейшим изменением API было бы сделать объект, возвращенный FindControl() объектом Builder-esque (где все установленные методы возвращают 'this'):
Page.FindControl("LocationDropDownList")
.setVisible(true)
.setSelectedValue(isAdmin ? "111" : "123");
Ответ 6
Это интересное использование расширений, и я ценю это только в этой заслуге. Я не уверен, что буду использовать его, но если вашей команде это нравится, то, во что бы то ни стало, используйте его.
Ответ 7
Это некорректный метод расширения, если я когда-либо видел его!
Ответ 8
Это просто разные стили кодирования, что вы подразумеваете под "слишком большим отъездом"? Отъезд от чего? Из чего вы привыкли? Только вы можете это решить. Я скажу, что блок VB With
принес больше вреда, чем пользы для чтения кода, и я бы не стал пытаться реплицировать поведение на С#, но это только мои предпочтения.
Я почти всегда использую это для 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");
Ответ 9
Мне больше нравится первая версия. Для чтения и понимания требуется меньше времени. Я согласен с тем, что методы расширения также хороши, если вы знакомы с ним, а также знакомы с методом With, но в чем его преимущество в этом случае?
Ответ 10
Незначительное примечание. Из личного опыта я бы изменил:
if(isAdmin)
ddl.SelectedValue = "111";
to
if(isAdmin) {
ddl.SelectedValue = "111";
}
или
if(isAdmin)
{
ddl.SelectedValue = "111";
}
Это позволит вам сэкономить время в отладке рано или поздно.
Ответ 11
Если это была языковая функция:
With(Page.FindControl("LocationDropDownList") as DropDownList)
{
Visible = true;
SelectedValue = "123";
if(isAdmin)
Add(new ListItem( "111"));
}
Вы выиграли бы что-то:
- избежать избыточности мутированного объекта
- все функции языка, доступные в блоке "С"
Выше пытается подражать стилю, не пожинув преимущества. Cargo Cult.
(Примечание: я понимаю различные аргументы против него, но все равно было бы неплохо)
Кстати, некоторые из моих помощников интерфейса С++ Win32 UI содержат сеттеры, которые используют цепочку аналогичных тем, чего вы хотите достичь:
LVItem (m_lc, idx).SetText(_T ( "Hello" )). SetImg (12).SetLParam(id);
В этом случае я наименее выигрываю "отсутствие избыточности", но это потому, что у меня нет свойств.
Ответ 12
Мои 2 цента: Это выглядит хорошо, мой единственный комментарий: "С" подразумевает что-то вроде "Где" или "Наличие", когда вы на самом деле устанавливаете свойство. Я бы предложил метод имя что-то вроде "Do", "Execute" или "Set", но, возможно, это просто мое странное мировоззрение.
Как насчет:
Page.WithControl<DropDownList>("LocationDropDownList")
.Do(d => d.Visible = true)
.Do(d => d.SelectedValue = "123")
.DoIf(isAdmin, d => d.Items.Add(new ListItem("Admin", "1")));
Ответ 13
Я предсказываю, что весь "свободный интерфейс" станет "венгерской нотацией" 2000-х годов. Я лично считаю, что это не выглядит очень чистым, и он рискует стать очень непоследовательным, если у вас есть несколько разработчиков, каждый со своими предпочтениями.
Ответ 14
Похоже, что ваш сотрудник - Лэмба Джанки.
Ответ 15
Я думаю, что вопрос читаемости субъективен, и у меня лично нет проблем с тем, что вы сделали. Я бы подумал использовать его, если ваша организация "одобрила" его.
Я думаю, что концепция звучит, и если вы изменили "С" на "Пусть", это будет более "функциональным" или "F # -ish". Личное мнение.
Page.FindControl("LocationDropDownList")
.CastAs<DropDownList>()
.Let(d => d.Visible = true)
.Let(d => d.SelectedValue = "123");
Ответ 16
Я бы сказал, что придерживаюсь первой версии. То, что вы опубликовали, слишком умно, чтобы сразу же было полезно кому-то прочитать код.
Вы даже можете пойти дальше и покончить с этим "var":
DropDownList ddl = (DropDownList) Page.FindControl("ddlName");
Ответ 17
Это прекрасный учебный пример о том, как сделать что-то более сложное, чем это должно быть.
Первая версия понятна и не требует дополнительных знаний, кроме обычных языков.
Ответ 18
Я говорю палку с первой версией без методов расширения или выражений lamba. Это относительно новые концепции, поэтому не многие разработчики будут иметь дескриптор для них, но вне их использования при извлечении/обработке данных из базы данных. Если вы их используете, у вас может быть удар по стоимости обслуживания. Приятно сказать "прочитайте, если это греческий для вас"; но в реальной жизни это может быть наилучшим подходом.
Ответ 19
Что касается "Свободного интерфейса", С# уже имеет отличный синтаксис для инициализаторов, который (IMHO) лучше, чем попытка использовать свободный стиль. Конечно, в вашем примере вы не инициализируете новый объект, вы меняете существующий. Вся моя экспертиза с Fluent интерфейсами связана с 30-секундным просмотром wikipedia, но я думаю, что ответ JeeBee больше соответствует духу Fluent программирование, хотя я могу немного изменить ситуацию:
Page.FindDropDownList("LocationDropDownList")
.setVisible(true)
.setAdminSelectedValue("111")
.setSelectedValue("123")
Можно утверждать, что это более читаемо, особенно для языка без свойств, но я все еще думаю, что это не имеет смысла в С#.
Ответ 20
В определенных обстоятельствах тщательно продуманные встроенные интерфейсы могут быть очень полезными. Во-первых, поскольку разработчику представлено ограниченное количество опций, они (как правило) просты в использовании правильно и трудны в использовании неправильно. Во-вторых, из-за предложения, подобного структуре, они могут быть хорошим чистым способом объявить ваши намерения, особенно при создании сложных объектов.
Я обнаружил, что свободные интерфейсы очень полезны при разработке тестового кода, в котором часто приходится создавать множество объектов домена с небольшими вариациями. Я также успешно использовал их в качестве способа введения шаблона декоратора и устранения чрезмерной перегрузки методов.
Если кто-то заинтересован в более подробном ознакомлении с текущими интерфейсами, я предлагаю проверить этот работа в процессе Мартина Фаулера.
Ответ 21
Хорошее эмпирическое правило:
Если ваше первое впечатление о вашем коде - "Это умно" - это, вероятно, не очень хорошая идея..
Хороший код должен быть простым, читаемым и только "умным", если это абсолютно необходимо.