反映参数名称:滥用C#lambda表达式或语法辉煌?
我正在查看MvcContrib Grid组件,并且我着迷于它,但同时还击退了Grid语法中使用的语法技巧:
.Attributes(style => "width:100%")
上面的语法将生成的HTML的样式属性设置为width:100%
。 现在,如果您注意,'风格'无处指定,则从表达式中的参数名称推断出来! 我不得不深入研究并找到'魔法'发生的地方:
Hash(params Func<object, TValue>[] hash)
{
foreach (var func in hash)
{
Add(func.Method.GetParameters()[0].Name, func(null));
}
}
所以确实,代码使用参数的形式,编译时间和名称来创建属性名称 - 值对的字典。 由此产生的语法结构确实非常具有表现力,但同时也非常危险。 一般使用lambda表达式可以替换所使用的名称而不会产生副作用。 我在书中看到一个例子,说collection.ForEach(book => Fire.Burn(book))
我知道我可以写我的代码collection.ForEach(log => Fire.Burn(log))
,它意味着相同事情。 但是,在这里使用MvcContrib Grid语法突然间,我发现代码会根据我为变量选择的名称进行主动查找并进行分解!
那么C#3.5 / 4.0社区和lambda表达式爱好者的这种常见做法是什么? 或者是我不应该担心的流氓特技特立独行?
互操作性差。 例如,考虑这个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语言进行良好的互操作性的话。
我觉得这并不是因为这个名字,而是因为lambda是不必要的 。 它可以使用匿名类型并且更灵活:
.Attributes(new { style = "width:100%", @class="foo", blip=123 });
这是ASP.NET MVC(例如)中大部分使用的模式,并且还有其他用途(请注意Ayende的想法,如果名称是魔术值而不是调用者特定的)
只是想抛出我的意见(我是MvcContrib网格组件的作者)。
这绝对是语言滥用 - 毫无疑问。 然而,我并不认为这是直观的 - 当你看一个对Attributes(style => "width:100%", @class => "foo")
的调用Attributes(style => "width:100%", @class => "foo")
我认为这很明显发生了什么(它肯定不比匿名类型的方法更糟糕)。 从intellisense的角度来看,我认为它非常不透明。
对于那些感兴趣的,一些关于它在MvcContrib中使用的背景信息...
我将它作为个人偏好添加到网格中 - 我不喜欢使用匿名类型作为词典(具有一个参数,它使用“object”与使用params Func []一样不透明),而Dictionary集合初始化程序是比较冗长(我也不喜欢详细的流畅接口,例如必须将多个调用链接到一个Attribute(“style”,“display:none”)。Attribute(“class”,“foo”)等)
如果C#对字典文字的语法较少,那么我不会在网格组件中包含这种语法。
我也想指出,在MvcContrib中使用这个是完全可选的 - 这些是扩展方法,它们包含了一个接受IDictionary的重载。 我认为重要的是,如果您提供这样的方法,您还应该支持更“常规”的方法,例如与其他语言进行互操作。
另外,有人提到了'反射开销',我只想指出,这种方法确实没有多少开销 - 没有涉及运行时反射或表达式编译(参见http://blog.bittercoder.com /PermaLink,guid,206e64d1-29ae-4362-874b-83f5b103727f.aspx)。
链接地址: http://www.djcxy.com/p/21207.html上一篇: Reflecting parameter name: abuse of C# lambda expressions or Syntax brilliance?