我看着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设计中,我会选择更明确的方式。

其他回答

如果方法(func)名称选择得当,那么这是避免维护头痛的好方法(例如:添加一个新的func,但忘记将其添加到函数参数映射列表中)。当然,你需要对它进行大量的文档记录,你最好从该类函数的文档中自动生成参数的文档……

恕我直言,这是一种很酷的方式。我们都喜欢将类命名为控制器将使其成为MVC中的控制器,对吧?所以在某些情况下,命名确实很重要。

这里的意图也很明确。很容易理解,.Attribute(book= > "something")将导致book="something", .Attribute(log= > "something")将导致log="something"

我想如果你把它当作一种惯例来对待,那应该不成问题。我的观点是,只要能让你写更少的代码,让你的意图更明显,那就是一件好事。

这是一个有趣的方法。如果你约束右边的表达式为常数,那么你可以实现使用

Expression<Func<object, string>>

我认为这才是你真正想要的,而不是委托(你使用lambda来获得两边的名称) 参见下面的naive实现:

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;
}

这甚至可以解决前面提到的跨语言互操作问题。

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

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

Cons

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

Pros

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

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

我更喜欢

Attributes.Add(string name, string value);

它更加明确和标准,使用lambdas什么也得不到。