反映参数名称:滥用 C# lambda 表达式还是语法高明?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1718037/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 20:13:52  来源:igfitidea点击:

Reflecting parameter name: abuse of C# lambda expressions or Syntax brilliance?

c#asp.net-mvclambdamvccontrib

提问by Remus Rusanu

I am looking at the MvcContribGrid component and I'm fascinated, yet at the same time repulsed, by a syntactic trick used in the Grid syntax:

我正在查看MvcContribGrid 组件,我很着迷,但同时又被Grid 语法中使用的句法技巧所排斥:

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

The syntax above sets the style attribute of the generated HTML to width:100%. Now if you pay attention, 'style' is nowhere specified, is deduced from the nameof the parameter in the expression! I had to dig into this and found where the 'magic' happens:

上面的语法将生成的 HTML 的 style 属性设置为width:100%. 现在,如果您注意,'style' 没有指定,是从表达式中的参数名称推导出来的!我不得不深入研究并找到“魔法”发生的地方:

Hash(params Func<object, TValue>[] hash)
{
    foreach (var func in hash)
    {
        Add(func.Method.GetParameters()[0].Name, func(null));
    }
}

So indeed, the code is using the formal, compile time, name of parameters to create the dictionary of attribute name-value pairs. The resulted syntax construct is very expressive indeed, but at the same time very dangerous. The general use of lambda expressions allows for replacement of the namesused without side effect. I see an example in a book that says collection.ForEach(book => Fire.Burn(book))I know I can write in my code collection.ForEach(log => Fire.Burn(log))and it means the same thing. But with the MvcContrib Grid syntax here all of a sudden, I find code that actively looks and makes decisions based on the names I choose for my variables!

因此,代码确实使用正式的、编译时的参数名称来创建属性名称-值对的字典。结果语法结构确实非常具有表现力,但同时也非常危险。lambda 表达式的一般用途允许在没有副作用的情况下替换使用的名称。我在一本书中看到一个例子,它说collection.ForEach(book => Fire.Burn(book))我知道我可以用我的代码编写collection.ForEach(log => Fire.Burn(log))这意味着同样的事情。但是突然之间有了 MvcContrib Grid 语法,我发现代码会主动查看并根据我为变量选择的名称做出决定!

So is this common practice with the C# 3.5/4.0 community and the lambda expressions lovers? Or is a rogue one trick maverick I shouldn't worry about?

那么这是 C# 3.5/4.0 社区和 lambda 表达式爱好者的常见做法吗?还是流氓一招特立独行,我不应该担心?

采纳答案by Brian

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

这具有较差的互操作性。例如,考虑这个 C# - F# 示例

C#:

C#:

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

F#:

F#:

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

Result:

结果:

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

打印“arg”(不是“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.

因此,库设计者应该避免这些类型的“滥用”,或者至少提供“标准”重载(例如,将字符串名称作为额外参数),如果他们想要跨 .Net 语言有良好的互操作。

回答by NotDan

I would prefer

我会选择

Attributes.Add(string name, string value);

It's much more explicit and standard and nothing is being gained by using lambdas.

它更加明确和标准,使用 lambda 没有任何好处。

回答by Jamie Penney

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.

这是表达式树的好处之一——可以检查代码本身以获取额外信息。那就是如何.Where(e => e.Name == "Jamie")可以转换成等效的 SQL Where 子句。这是表达式树的巧妙使用,尽管我希望它不会比这更进一步。任何更复杂的东西都可能比它希望替换的代码更难,所以我怀疑它会自我限制。

回答by Blindy

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!

我在“语法辉煌”阵营,如果他们清楚地记录它,并且它看起来非常酷,那么它几乎没有问题imo!

回答by Jason Punyon

Welcome To Rails Land :)

欢迎来到 Rails Land :)

There is really nothing wrong with it as long as you know what's going on. (It's when this kind of thing isn't documented well that there is a problem).

只要你知道发生了什么,它真的没有错。(当这种事情没有得到很好的记录时,就会出现问题)。

The entirety of the Rails framework is built on the idea of convention over configuration. Naming things a certain way keys you into a convention they're using and you get a whole lot of functionality for free. Following the naming convention gets you where you're going faster. The whole thing works brilliantly.

整个 Rails 框架都建立在约定优于配置的思想之上。以某种方式命名事物可以让您进入他们正在使用的约定,并且您可以免费获得大量功能。遵循命名约定可以让您更快地到达目的地。整个过程都非常出色。

Another place where I've seen a trick like this is in method call assertions in Moq. You pass in a lambda, but the lambda is never executed. They just use the expression to make sure that the method call happened and throw an exception if not.

我见过这样的技巧的另一个地方是在 Moq 中的方法调用断言中。您传入一个 lambda,但该 lambda 永远不会执行。他们只是使用表达式来确保方法调用发生,否则抛出异常。

回答by Elisha

I hardly ever came across this kind of usage. I think it's "inappropriate" :)

我几乎没有遇到过这种用法。我认为这是“不合适的”:)

This is not a common way of use, it is inconsistent with the general conventions. This kind of syntax has pros and cons of course:

这不是一种常见的使用方式,它与一般约定不一致。这种语法当然有利有弊:

Cons

缺点

  • The code is not intuitive (usual conventions are different)
  • It tends to be fragile (rename of parameter will break the functionality).
  • It's a little more difficult to test (faking the API will require usage of reflection in tests).
  • If expression is used intensively it'll be slower due to the need to analyze the parameter and not just the value (reflection cost)
  • 代码不直观(通常约定不同)
  • 它往往很脆弱(重命名参数会破坏功能)。
  • 测试有点困难(伪造 API 将需要在测试中使用反射)。
  • 如果表达式被密集使用,由于需要分析参数而不仅仅是值(反射成本),它会变慢

Pros

优点

  • It's more readable after the developer adjusted to this syntax.
  • 开发人员调整到此语法后,它的可读性更高。

Bottom line- in public API design I would have chosen more explicit way.

底线- 在公共 API 设计中,我会选择更明确的方式。

回答by Guffa

No, it's certainly not common practice. It's counter-intuitive, there is no way of just looking at the code to figure out what it does. You have to know how it's used to understand how it's used.

不,这当然不是常见的做法。这是违反直觉的,没有办法仅仅查看代码来弄清楚它的作用。你必须知道它是如何使用的才能理解它是如何使用的。

Instead of supplying attributes using an array of delegates, chaining methods would be clearer and perform better:

与使用委托数组提供属性不同,链接方法会更清晰且性能更好:

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

Although this is a bit more to type, it's clear and intuitive.

虽然输入的内容有点多,但它清晰直观。

回答by Craig Trader

If the method (func) names are well chosen, then this is a brilliant way to avoid maintenance headaches (ie: add a new func, but forgot to add it to the function-parameter mapping list). Of course, you need to document it heavily and you'd better be auto-generating the documentation for the parameters from the documentation for the functions in that class...

如果方法 (func) 名称选择得当,那么这是避免维护麻烦的绝妙方法(即:添加新的 func,但忘记将其添加到函数参数映射列表中)。当然,您需要大量记录它,并且最好从该类中的函数的文档中自动生成参数的文档......

回答by mfeingold

In my opinion it is abuse of the lambdas.

在我看来,这是对 lambda 的滥用。

As to syntax brilliance i find style=>"width:100%"plain confusing. Particularily because of the =>instead of =

至于语法的才华,我觉得很style=>"width:100%"容易混淆。Particularily因为=>代替=

回答by Chris R. Timmons

The code is very clever, but it potentially causes more problems that it solves.

该代码非常聪明,但它可能会导致它解决的更多问题。

As you've pointed out, there's now an obscure dependency between the parameter name (style) and an HTML attribute. No compile time checking is done. If the parameter name is mistyped, the page probably won't have a runtime error message, but a much harder to find logic bug (no error, but incorrect behavior).

正如您所指出的,现在参数名称(样式)和 HTML 属性之间存在一种模糊的依赖关系。没有进行编译时检查。如果参数名称输入错误,页面可能不会有运行时错误消息,但更难找到逻辑错误(没有错误,但行为不正确)。

A better solution would be to have a data member that can be checked at compile time. So instead of this:

更好的解决方案是拥有一个可以在编译时检查的数据成员。所以而不是这个:

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

code with a Style property could be checked by the compiler:

编译器可以检查带有 Style 属性的代码:

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

or even:

甚至:

.Attributes.Style.Width.Percent = 100;

That's more work for the authors of the code, but this approach takes advantage of C#'s strong type checking ability, which helps prevent bugs from getting into code in the first place.

这对代码的作者来说是更多的工作,但这种方法利用了 C# 强大的类型检查能力,这有助于首先防止错误进入代码。