Implicit Cast of Lambda Expression to Custom Class in C# 3.0?
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!