Csc.exe and delegate inference, or: Why C# has awkward syntax
I just tried to to do a major revamp of Rhino Mocks' interface. It was intended to make it easier to work with C# 3.0 and use the smarter compiler to get better syntax.
I shouldn't have bothered. Take a look at this.
public class TestCsc { public static void TestMethod() { Execute(Bar); // fail to compile Execute(delegate(int ia, string x) { }); // compiles fine Execute((int i, string x) => { return; }); // Compiles fine Execute((int i, string x) => { return true; }); // fail to compile Execute(Foo);// fail to compile Execute(delegate(int ia, string x) { return true; }); // fail to compile } public static bool Foo(int ia, string x) { return false; } public static void Bar(int ia, string x) { } public static void Execute<T, K>(Action<T, K> e) { } public static void Execute<T, K>(Func<bool, T, K> e) { } }
Annoyed.
Comments
Maybe you were looking for Func<T, K, bool>?
public static void Execute<T, K>(Func<bool, T, K> e)
should be
public static void Execute<T, K>(Func<T, K,bool> e)
:)
after that there will be errors only with
Execute(Bar);
Execute(Foo);
you can rewrite this as
Here is big explanation why type inference didn't work in this case:
http://blogs.msdn.com/ericlippert/archive/2007/11/05/c-3-0-return-type-inference-does-not-work-on-member-groups.aspx
But for me that was not very convincing.
Lambda stuff is nice but I would love to see Boo DSL for rhino mocks :)
Yes, this is pretty annoying. I ran into this as well when I wanted to introduce some types for prefetchpath specifications inside linq queries and wanted to get rid of the explicit generic argument specifications... IMHO it's a compiler flaw, no matter how many excuses they invent: they introduced syntactic sugar, then make the compiler deal with that in all cases.
If you swap the bool on the end to Func<T, K, bool> then everything except for Execute(Bar) and Execute(Foo) works. And I agree with Frans, I have heard all the explanations about why it wouldn't work, but I wish they could have found a way to make it work.
Let me also say that they could have enabled this for very simple scenarios such as the one you are dealing with. In the blog post by Eric Lippert referenced above he basically says that they could have done it in certain scenarios, but in other scenarios it would have been impossible. He said that they didn't want two different inference algorithms that produce slightly different results. While I am certainly not a compiler writer, that sounds like they are taking an idealistic approach and not a pragmatic one. The pragmatic approach would have been to try and make type inference work in as many different scenarios as possible, and have it fail when the resolution is unreachable.
Execute((t, k) => Bar(t, k));
Execute((t, k) => Foo(t, k));
I now your pain, earlier this week, I've been trying to come up with nicer, and more strongly typed ways to cope with events in Rhino.Mocks (strongly typed EventRaiser, event subscribtion and verification) and I failed miserably. I think I just gave up (at least for now). You can see the attempts at my blog.
And BTW, why are delegates so limited in cooperation with generics? :/ It's just annoying
Comment preview