This entry was posted on Tuesday, August 12th, 2008 at 10:23 am and is filed under Tech Stuff. You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.
We hit a little speed bump in our work with parameter-less lambdas - we wanted to be able to assign them to objects of a custom class via an implicit cast, this is very important to our cunning plan…
To illustrate this consider the following class that just encapsulates a 0-arity delegate Func<T>:
public class RuleProp<T>
{
private Func<T> _lambda = null;
public RuleProp(Func<T> l)
{
_lambda = l;
}
public static implicit operator RuleProp<T>(Func<T> l)
{
return new RuleProp<T>(l);
}
public RuleProp()
{
}
}
Now, because we have specified an implicit cast for: Func<T> -> RuleProp<T>, it would seem that we should be able to do the following:
var rp = new RuleProp<string>(); rp = () => "hello"; // Not OK, can't convert lambda to delegate
But this gives us a compiler error, can’t convert lambda to Fun<T> as it’s not a delegate!! Looking at the C# specification it seems that if more than one implicit conversion is required, the C# compiler will only do one. In this case 2 conversions are required:
Lambda Expression -> Func<T> -> RuleProp<T>
And so the compiler can’t handle it. If we provide an explicit cast to Func<T> it compiles OK:
rp = (Func<string>)(() => "hello"); // Cast works..
But this is really ugly as the type must be provided each time. A workaround was suggested in this article:
http://www.interact-sw.co.uk/iangblog/2008/03/17/lambda-inference
We provide an ‘adaptor’ function which encourages a cast from Lambda -> Func<T>, and the implicit cast from Func<T> to RuleProp<T> will handle the rest, we can use it like this:
rp = Adaptor(() => "hello"); // Now OK!
This is much nicer than the explicit cast as no type needs to be specified! Here is the function, it just take,s and directly returns a delegate - resulting in just the conversion that we need!
public static Func<T> Adaptor<T>(Func<T> f)
{
return f;
}
So although it is not as nice as directly assigning a lambda to RuleProp<T> it’s a grand workaround and will do nicely for the time being - thanks to all at the C# MSDN forum for their help!
