我看着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表达式爱好者的普遍做法吗?还是说,我不应该担心一个流氓的诡计特立独行?


当前回答

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

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

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

其他回答

我发现奇数不是因为它的名字,而是因为没有必要;它可以使用匿名类型,并且更加灵活:

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

这是在很多ASP中使用的模式。NET MVC(例如),并有其他用途(注意,如果名称是一个魔法值,而不是特定于调用者,也要注意Ayende的想法)

这是表达式树的好处之一——可以检查代码本身以获得额外的信息。这就是如何将.Where(e => e. name == "Jamie")转换为等效的SQL Where子句。这是表达式树的一种巧妙使用,尽管我希望它不会超出这个范围。任何更复杂的代码都可能比它希望取代的代码更难,因此我怀疑它将是自我限制的。

我能用这个词造个词吗?

Magic lambda (n):仅用于替换魔术字符串的lambda函数。

的确,它看起来像Ruby =),至少对我来说,使用静态资源进行以后的动态“查找”不适合api设计的考虑,希望这个聪明的技巧是可选的api。

当你不需要添加键来设置值时,我们可以继承(或不继承)IDictionary并提供一个像php数组一样的索引器。它将是.net语义的有效使用,而不仅仅是c#,并且仍然需要文档。

希望这能有所帮助

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

而不是使用委托数组提供属性,链接方法将更清晰,性能更好:

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

虽然输入起来有点费劲,但它清晰直观。