I find that odd not so much because of the name, but because the lambda is unnecessary; it could use an anonymous-type and be more flexible:
.Attributes(new { style = "width:100%", @class="foo", blip=123 });
This is a pattern used in much of ASP.NET MVC (for example), and has other uses (a caveat, note also Ayende's thoughts if the name is a magic value rather than caller-specific)
This has poor interop. For example, consider this C# - F# example
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")
Result:
"arg" is printed (not "yadda").
As a result, library designers should either avoid these kinds of 'abuses', or else at least provide a 'standard' overload (e.g. that takes the string name as an extra parameter) if they want to have good interop across .Net languages.
Just wanted to throw in my opinion (I'm the author of the MvcContrib grid component).
This is definitely language abuse - no doubt about it. However, I wouldn't really consider it counter intuitive - when you look at a call to Attributes(style => "width:100%", @class => "foo")
I think it's pretty obvious what's going on (It's certainly no worse than the anonymous type approach). From an intellisense perspective, I agree it is pretty opaque.
For those interested, some background info on its use in MvcContrib...
I added this to the grid as a personal preference - I do not like the use of anonymous types as dictionaries (having a parameter that takes "object" is just as opaque as one that takes params Func[]) and the Dictionary collection initializer is rather verbose (I am also not a fan of verbose fluent interfaces, eg having to chain together multiple calls to an Attribute("style", "display:none").Attribute("class", "foo") etc)
If C# had a less verbose syntax for dictionary literals, then I wouldn't have bothered including this syntax in the grid component :)
I also want to point out that the use of this in MvcContrib is completely optional - these are extension methods that wrap overloads that take an IDictionary instead. I think it's important that if you provide a method like this you should also support a more 'normal' approach, eg for interop with other languages.
Also, someone mentioned the 'reflection overhead' and I just wanted to point out that there really isn't much of an overhead with this approach - there is no runtime reflection or expression compilation involved (see http://blog.bittercoder.com/PermaLink,guid,206e64d1-29ae-4362-874b-83f5b103727f.aspx).
I would prefer
Attributes.Add(string name, string value);
It's much more explicit and standard and nothing is being gained by using lambdas.
Welcome To Rails Land :)
There is really nothing wrong with it as long as you know what's going on. (It's when this kind of thing isn't documented well that there is a problem).
The entirety of the Rails framework is built on the idea of convention over configuration. Naming things a certain way keys you into a convention they're using and you get a whole lot of functionality for free. Following the naming convention gets you where you're going faster. The whole thing works brilliantly.
Another place where I've seen a trick like this is in method call assertions in Moq. You pass in a lambda, but the lambda is never executed. They just use the expression to make sure that the method call happened and throw an exception if not.
This is horrible on more than one level. And no, this is nothing like Ruby. It's an abuse of C# and .NET.
There have been many suggestions of how to do this in a more straightforward way: tuples, anonymous types, a fluent interface and so on.
What makes it so bad is that its just way to fancy for its own good:
What happens when you need to call this from Visual Basic?
.Attributes(Function(style) "width:100%")
It's completely counter intuitive, and intellisense will provide little help figuring out how to pass stuff in.
It's unnecessarily inefficient.
Nobody will have any clue how to maintain it.
What is the type of the argument going in to attributes? is it Func<object,string>
? How is that intention revealing? What is your intellisense documentation going to say, "Please disregard all values of object"?
I think you are completely justified having those feelings of revulsion.
I'm in the "syntax brilliance" camp, if they document it clearly, and it looks this freaking cool, there's almost no problem with it imo!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With