Implicit Cast of Lambda Expression to Custom Class via delegate

Question

Monday, August 11, 2008 1:11 PM

Hi all,

I have a query that about assigning and casting lambda expressions that I hope you can help me with; it has had me scratching my head a bit!.  Let's say that I have a little class that encapsulates a parameter-less delegate of return type T as follows:

        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()  
            {  
            }  
        }  
 

I had hoped that the implicit cast would allow to assign an appropriate lambda expression as follows:

            var rp = new RuleProp<string>();  
 
            rp = () => "hello"; // Not OK, can't convert lambda to delegate  
 

However the compiler reports an error saying that it can't convert the lambda expression to type because it's not a delegate.  However, it works OK with an explicit cast:

            rp = (Func<string>)(() => "hello"); // OK with explicit cast..  
 

Does anybody know if such an implicit cast is possible in c# or will I have to make do with inserting an explicit cast all the time (pain)?  When calling the constructor the compiler is willing & able to convert the lambda expression to Func<T> but it does not seem to be willing to do the same for the implicit cast...

Thanks for reading!

Kevin.

 


Ridge Solutions

All replies (5)

Tuesday, August 12, 2008 1:50 AM ✅Answered

I found the blog where I had read about Lambdas compiling to either Expressions or Delegates:
http://www.interact-sw.co.uk/iangblog/2008/03/17/lambda-inference

His solution may help you.


Tuesday, August 12, 2008 5:34 AM ✅Answered

It is discussed in section 6.5 of the C# 3.0 standard:

An anonymous-method-expression or lambda-expression is classified as an anonymous function (§7.14). The expression does not have a type but can be implicitly converted to a compatible delegate type or expression tree type.

Your statement requires two implicit conversions, the C# compiler will consider only one.


Hans Passant.


Monday, August 11, 2008 4:59 PM

I suspect that the root of this is related to the fact that Lambdas can be compiled to either an Expression or a Delegate. 

Maybe there is some other special cast restrictions going on in the background that allows lambdas to be cast to delegates in function parameters and assignment, but not during assignment with implicit operators.

var a = new RuleProp<string>(() => "hello1"); //Works 
Func<String> tempA = () => "hello2"; a = tempA; //Also works 
a = () => "hello3"; //No worky 

Perhaps you need to specify another implicit operator to help tell the compile what you want?


Monday, August 11, 2008 6:05 PM

 I agree,

it does seem strange to me that the compiler will happily convert an expression into a delegate for a function call but will not do the same for the cast.  I have tried all sorts of other casts and intermediate things with no luck.  I suppose the compiler is just being very careful or something, I know a lot of people don't really like the idea of implicit casts at all as they can sometimes lead to unintended behavior...

Thanks!

 


Kevin Godden - Ridge Solutions


Tuesday, August 12, 2008 8:12 AM

Hi all,

Thanks very much for all your replies - they are very much appreciated!

So from your posts, it seems that in this case 2 implicit conversions are required,

Lambda Exp. -> Func<T> -> RuleProp

And whereas the c# compiler is happy to do one of them, it won't do both.  So I suppose we will have to help it along by doing one of the steps for it.  From the article provided by cncarson (http://www.interact-sw.co.uk/iangblog/2008/03/17/lambda-inference) it would seem that an adaptor function like the following might help, it will force the first conversion leaving the compiler to do the second:

        public static Func<T> Adaptor<T>(Func<T> f)  
        {  
            return f;  
        }  
 

And indeed it does! it's not perfect but it is a much better option than the cast as the type does not need to be provided:

            rp = Adaptor(() => "hello"); // Now OK! & nicer than the cast below!  
 
            rp = (Func<string>)(() => "hello"); // Cast works too, but have to provide type  
 

So I reckon this is as good a workaround as any - sorted!, thanks again to for all your help!

Kevin.