Отражение имени параметра: злоупотребление лямбда-выражениями C # или синтаксический блеск?

SELECT varchar_col
FROM table
GROUP BY varchar_col
HAVING count(*) > 1;
422
задан 5 revs, 5 users 66% 7 March 2019 в 17:15
поделиться

21 ответ

This has poor interop. For example, consider this C# - F# example

C#:

public class Class1
{
    public static void Foo(Func<object, string> f)
    {
        Console.WriteLine(f.Method.GetParameters()[0].Name);
    }
}

F#:

Class1.Foo(fun yadda -> "hello")

Result:

"arg" is printed (not "yadda").

As a result, library designers should either avoid these kinds of 'abuses', or else at least provide a 'standard' overload (e.g. that takes the string name as an extra parameter) if they want to have good interop across .Net languages.

146
ответ дан 22 November 2019 в 23:20
поделиться

Если имена методов (функций) выбраны правильно, то это отличный способ избежать головной боли при обслуживании (например: добавить новую функцию, но забыть добавить ее в отображение параметров функции список). Конечно, вам необходимо тщательно задокументировать это, и вам лучше автоматически создавать документацию для параметров из документации для функций этого класса ...

3
ответ дан 22 November 2019 в 23:20
поделиться

действительно похоже на Ruby =), по крайней мере, для меня использование статического ресурса для последующего динамического "поиска" не подходит для соображений дизайна api, надеюсь, этот хитрый трюк необязателен в этом API.

Мы могли бы унаследовать от IDictionary (или нет) и предоставить индексатор, который ведет себя как массив php, когда вам не нужно добавлять ключ для установки значения. Это будет допустимое использование семантики .net, а не только C #, и все еще потребуется документация.

надеюсь, что это поможет

5
ответ дан 22 November 2019 в 23:20
поделиться

На мой взгляд, это злоупотребление лямбдами.

Что касается блеска синтаксиса, я считаю, что style => "width: 100%" просто сбивает с толку. В частности, из-за => вместо =

4
ответ дан 22 November 2019 в 23:20
поделиться

Код очень умный, но он потенциально вызывает больше проблем, которые он решает.

Как вы отметили, теперь существует неясная зависимость между именем параметра (стилем) и атрибутом HTML . Проверка времени компиляции не выполняется. Если имя параметра введено с ошибкой, на странице, вероятно, не будет сообщения об ошибке времени выполнения, но будет намного сложнее найти логическую ошибку (нет ошибки, но неправильное поведение).

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

.Attributes(style => "width:100%");

код со свойством Style может быть проверен компилятором:

.Attributes.Style = "width:100%";

или даже:

.Attributes.Style.Width.Percent = 100;

Это больше работы для авторов кода, но этот подход использует преимущества C # '

6
ответ дан 22 November 2019 в 23:20
поделиться

This is one of the benefits of expression trees - one can examine the code itself for extra information. That is how .Where(e => e.Name == "Jamie") can be converted into the equivalent SQL Where clause. This is a clever use of expression trees, though I would hope that it does not go any further than this. Anything more complex is likely to be more difficult than the code it hopes to replace, so I suspect it will be self limiting.

12
ответ дан 22 November 2019 в 23:20
поделиться

Нет, это определенно не обычная практика. Это противоречит интуиции, нет возможности просто взглянуть на код, чтобы понять, что он делает. Вы должны знать, как это используется, чтобы понять, как это используется.

Вместо предоставления атрибутов с использованием массива делегатов методы цепочки будут более ясными и эффективными:

.Attribute("style", "width:100%;").Attribute("class", "test")

Хотя это немного больше для ввода, это ясно и интуитивно понятный.

18
ответ дан 22 November 2019 в 23:20
поделиться

Я почти никогда не сталкивался с подобным использованием. Я думаю, что это «неуместно» :)

Это не обычный способ использования, он несовместим с общими соглашениями. У такого синтаксиса, конечно, есть свои плюсы и минусы:

Минусы

  • Код не интуитивно понятен (обычные соглашения разные)
  • Он имеет тенденцию быть хрупким (переименование параметра нарушит функциональность).
  • Это немного сложнее проверить (подделка API потребует использования отражения в тестах).
  • Если выражение используется интенсивно, оно будет медленнее из-за необходимости анализировать параметр, а не только значение (стоимость отражения)

Плюсы

  • Это более читабельно после того, как разработчик приспособился к этому синтаксису.

Итог - в общедоступном дизайне API я бы выбрал более явный путь.

21
ответ дан 22 November 2019 в 23:20
поделиться

Это ужасно более чем на одном уровне. И нет, это не похоже на Руби. Это злоупотребление C # и .Net.

Было много предложений, как сделать это более простым способом: кортежи, анонимные типы, свободный интерфейс и так далее.

Что делает его таким плохим, так это то, что это просто способ воображать себе во благо:

  • Что происходит, когда вам нужно вызвать это из VB?

    .Attributes (Function (style) "width: 100%" )

  • Его полностью противоречащий интуиции, intellisense мало поможет понять, как передавать данные.

  • Это излишне неэффективно.

  • Никто не поймет, как его поддерживать.

  • Какой тип аргумента передается в атрибуты, это Func ? Как это намерение раскрывается. Что в вашей документации intellisense будет сказано: «Пожалуйста, не обращайте внимания на все значения объекта»

? Я думаю, что вы полностью оправданы, испытывая такое чувство отвращения.

42
ответ дан 22 November 2019 в 23:20
поделиться

I'm in the "syntax brilliance" camp, if they document it clearly, and it looks this freaking cool, there's almost no problem with it imo!

40
ответ дан 22 November 2019 в 23:20
поделиться

Добро пожаловать в Rails Land :)

В этом нет ничего плохого, если вы знаете, что происходит. (Проблема возникает, когда подобные вещи плохо документированы).

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

Еще одно место, где я видел подобный трюк, - это утверждения вызова методов в Moq. Вы передаете лямбду, но она никогда не выполняется. Они просто используют выражение, чтобы убедиться, что вызов метода произошел, и в противном случае выдают исключение.

46
ответ дан 22 November 2019 в 23:20
поделиться

Я бы предпочел

Attributes.Add(string name, string value);

Он гораздо более явный и стандартный, и при использовании лямбда-выражений ничего не получается.

49
ответ дан 22 November 2019 в 23:20
поделиться

I find that odd not so much because of the name, but because the lambda is unnecessary; it could use an anonymous-type and be more flexible:

.Attributes(new { style = "width:100%", @class="foo", blip=123 });

This is a pattern used in much of ASP.NET MVC (for example), and has other uses (a caveat, note also Ayende's thoughts if the name is a magic value rather than caller-specific)

154
ответ дан 22 November 2019 в 23:20
поделиться

ИМХО, это крутой способ сделать это. Нам всем нравится тот факт, что присвоение имени классу Controller сделает его контроллером в MVC, верно? Так что есть случаи, когда название имеет значение.

Также здесь очень ясно намерение. Легко понять, что .Attribute (book => "something") приведет к book = "something" и .Attribute (log => "something" ) приведет к log = "something"

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

5
ответ дан 22 November 2019 в 23:20
поделиться

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

Expression<Func<object, string>>

Что, я думаю, это то, что вам действительно нужно вместо делегата (вы используете лямбда для получения имен обеих сторон) См. Наивную реализацию ниже:

public static IDictionary<string, string> Hash(params Expression<Func<object, string>>[] hash) {
    Dictionary<string, string> values = new Dictionary<string,string>();
    foreach (var func in hash) {
        values[func.Parameters[0].Name] = ((ConstantExpression)func.Body).Value.ToString();
    }
    return values;
}

Это может даже решить проблему межъязыкового взаимодействия, которая упоминалась ранее в потоке.

7
ответ дан 22 November 2019 в 23:20
поделиться

Просто хотел высказать свое мнение (я автор компонента сетки MvcContrib).

Это определенно злоупотребление языком - без сомнения. Однако я бы не стал считать это интуитивно понятным - когда вы смотрите на вызов Attributes (style => "width: 100%", @class => "foo")
, я думаю, что это довольно очевидно что происходит (это, конечно, не хуже, чем подход анонимного типа). С точки зрения intellisense, я согласен, что это довольно непрозрачно.

Для тех, кто интересуется, некоторая справочная информация о его использовании в MvcContrib ...

Я добавил это в сетку как личное предпочтение - мне не нравится использование анонимных типов в виде словарей (с параметром, принимающим "объект" столь же непрозрачен, как и тот, который принимает params Func []), а инициализатор коллекции Dictionary довольно многословен (я также не поклонник подробных беглых интерфейсов, например, необходимости объединять в цепочку несколько вызовов атрибута ("style", "display : none "). Attribute (" class "," foo ") и т.д.)

Если бы в C # был менее подробный синтаксис для словарных литералов, я бы не стал включать этот синтаксис в компонент сетки :)

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

Также кто-то упомянул «отражение наверху».

137
ответ дан 22 November 2019 в 23:20
поделиться

Могу ли я использовать это для создания фразы?

magic lambda (n): лямбда-функция, используемая исключительно с целью замены волшебной строки.

17
ответ дан 22 November 2019 в 23:20
поделиться

Думаю, это не лучше "волшебных ниток". Я тоже не очень люблю анонимные типы. Ему нужен лучший и строго типизированный подход.

1
ответ дан 22 November 2019 в 23:20
поделиться

Что не так со следующим:

html.Attributes["style"] = "width:100%";
17
ответ дан 22 November 2019 в 23:20
поделиться

Они оба. Это злоупотребление лямбда-выражениями И великолепным синтаксисом.

37
ответ дан 22 November 2019 в 23:20
поделиться

Вы пытаетесь использовать отрицаемый класс символов неверным путь. Отрицательный класс символов говорит, что «не соответствуют содержащимся символам». То, что вы хотите сказать, «не совпадают, если это то, что я указал здесь существует». Для этого нужно немного креативнее. Наверное, нужен негативный взгляд. Я не уверен на 100% в регуляторном двигателе PHP, но что-то подобное должно сработать.

/^\/(?<!(?:products|categories|admin))(.+)$/

так, отрицательный ответ (? не соответствует . + , если продукты или категории или admin предшествуют ему. Затем находится в группе без захвата (?:...) .

Дополнительные сведения см. в разделе Расширенная ссылка на синтаксис регулярного выражения .

-121--3071531-

Здесь вам нужно отрицательное утверждение . То, что вы хотите сказать, это «Я хочу соответствовать любой последовательности символов, кроме этих конкретных последовательностей». Утверждение в регексе может совпадать со последовательностью, но не использовать никаких символов, что позволяет сопоставлять этот символ с остальной частью регекса. Можно указать отрицательное утверждение, заключив образец в (?! и ) .

'/^\/(?!products|categories|admin)(.+)$/'

Обратите внимание, что вместо этого вам может понадобиться следующее:

'/^\/(?!products|categories|admin)([^/]+)$/'
-121--3071529-

Если вы не разрешаете клиентам включать косые черты, все это выражение о «ужасности» - куча давних c # парней, которые слишком реагируют (а я давний C # программист и все еще очень большой поклонник языка). В этом синтаксисе нет ничего ужасного. Это просто попытка сделать синтаксис более похожим на то, что вы пытаетесь выразить. Чем меньше «шума» в синтаксисе для чего-то, тем легче программист может его понять. Уменьшение шума в одной строке кода только немного помогает, но пусть это нарастает в большем и большем количестве кода, и это оказывается существенным преимуществом.

Это попытка автора стремиться к тем же преимуществам, которые дает вам DSL - когда код просто «выглядит как» то, что вы пытаетесь сказать, вы достигли волшебного места. Вы можете обсудить, хорошо ли это для взаимодействия, или достаточно лучше, чем анонимные методы, чтобы оправдать некоторые из «сложных» затрат. Справедливо... поэтому в вашем проекте вы должны сделать правильный выбор, использовать ли такой синтаксис. Но все же... это умная попытка программиста сделать то, что в конце дня мы все пытаемся сделать (осознаем мы это или нет). И что мы все пытаемся сделать, так это: «Сообщите компьютеру, что мы хотим, чтобы он делал на языке, максимально близком к тому, что мы думаем о том, что он хочет делать».

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

EDIT: Я сказал «ключ к тому, чтобы сделать программное обеспечение более ремонтопригодным и более точным», что является безумно наивной преувеличенной частью единообразия.Я изменил его на «ключ»

.
17
ответ дан 22 November 2019 в 23:20
поделиться
Другие вопросы по тегам:

Похожие вопросы: