我看着MvcContrib网格组件,我很着迷,但同时又被网格语法中使用的语法技巧所排斥:

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

上面的语法将生成的HTML的样式属性设置为width:100%。如果你注意的话,'style'并没有被指定。它是从表达式中参数的名称推导出来的!我必须深入研究这个问题,找到“魔法”发生的地方:

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

因此,代码确实使用了正式的、编译时的参数名称来创建属性名称-值对的字典。生成的语法结构确实非常具有表现力,但同时也非常危险。

lambda表达式的一般用法允许替换所使用的名称而不产生副作用。我在一本书上看到一个例子,上面写着收藏。我知道我可以在我的代码集合中写。ForEach(log => fire。burn (log))它的意思是一样的。但是使用这里的MvcContrib Grid语法,我突然发现代码可以根据我为变量选择的名称主动查找并做出决定!

那么这是c# 3.5/4.0社区和lambda表达式爱好者的普遍做法吗?还是说,我不应该担心一个流氓的诡计特立独行?


当前回答

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

这不是一种常用的使用方式,它不符合一般的约定。当然,这种语法也有优点和缺点:

Cons

代码不是直观的(通常的约定是不同的) 它往往是脆弱的(重命名参数将破坏功能)。 测试起来有点困难(伪造API需要在测试中使用反射)。 如果大量使用表达式,它会变慢,因为需要分析参数而不仅仅是值(反射成本)。

Pros

在开发人员调整到这种语法之后,它的可读性更强。

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

其他回答

欢迎来到Rails Land:)

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

整个Rails框架是建立在约定优于配置的思想之上的。以特定的方式命名事物将您带入他们正在使用的约定,并且您可以免费获得大量功能。遵循命名惯例可以让你更快地到达目的地。整个系统运作得非常出色。

我还在Moq中的方法调用断言中看到过类似的技巧。你传入一个lambda,但是lambda永远不会被执行。它们只是使用表达式来确保方法调用发生了,如果没有发生则抛出异常。

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

这不是一种常用的使用方式,它不符合一般的约定。当然,这种语法也有优点和缺点:

Cons

代码不是直观的(通常的约定是不同的) 它往往是脆弱的(重命名参数将破坏功能)。 测试起来有点困难(伪造API需要在测试中使用反射)。 如果大量使用表达式,它会变慢,因为需要分析参数而不仅仅是值(反射成本)。

Pros

在开发人员调整到这种语法之后,它的可读性更强。

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

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

至于语法辉煌,我发现style=>"width:100%"平原混乱。特别是因为=>而不是=

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

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

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

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

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

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

甚至:

.Attributes.Style.Width.Percent = 100;

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

我认为这不比“魔术弦”好多少。在这方面,我也不太喜欢匿名类型。它需要一种更好的强类型方法。