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


当前回答

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

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

希望这能有所帮助

其他回答

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

欢迎来到Rails Land:)

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

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

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

我属于“语法卓越”阵营,如果他们清楚地记录它,它看起来非常酷,在我看来几乎没有问题!

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

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

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

它的互操作性很差。例如,考虑这个c# - f#的例子

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")

结果:

打印“arg”(不是“yadda”)。

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