Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Lambda Expression Delegate Strong Type vs Weak Type implicit Convert Method

Tags:

c#

lambda

I've got an extension method that used to take a strongly typed Expression<Func<>> parameter however for implementation reasons I had to change it to use a weakly type version. This has had a strange affect on the expression parameter as it now seems to be wrapping the lambda expression in an explicit call to a 'Convert' method.

Previously the paramters would look like:

m => m.Data

And now it looks like the following:

m => Convert(m.Data)

I have replicated the issue with the following example code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;

namespace ConsoleApplication
{
    static class Program
    {
        static void Main(string[] args)
        {
            Model model = new Model()
            {
                Data = 123
            };

            Test(m => m.Data, m => m.Data);

            Console.ReadLine();                
        }

        public static void Test<TProperty>(Expression<Func<Model, TProperty>> strongTyped, Expression<Func<Model, object>> weakTyped)
        {
            Console.WriteLine("Strong Typed: {0}", strongTyped);
            Console.WriteLine("Weak Typed: {0}", weakTyped);
        }
    }

    public class Model
    {
        public int Data
        {
            get;
            set;
        }
    }
}

The output of which is as follows:

Strong Typed: m => m.Data
Weak Typed: m => Convert(m.Data)

I am guessing it has something to do with auto boxing the value type into an object type. Can anyone confirm this or does anyone know what is going on? Also does anyone know where the Convert method is declared?

Calling the compile method on the weak typed expression gives the following:

weakTyped.Compile().Method
{System.Object lambda_method(System.Runtime.CompilerServices.Closure, ConsoleApplication.Model)}
    [System.Reflection.Emit.DynamicMethod.RTDynamicMethod]: {System.Object lambda_method(System.Runtime.CompilerServices.Closure, ConsoleApplication.Model)}
    base {System.Reflection.MethodBase}: {System.Object lambda_method(System.Runtime.CompilerServices.Closure, ConsoleApplication.Model)}
    MemberType: Method
    ReturnParameter: null
    ReturnType: {Name = "Object" FullName = "System.Object"}
    ReturnTypeCustomAttributes: {System.Reflection.Emit.DynamicMethod.RTDynamicMethod.EmptyCAHolder}
like image 390
Tom Maher Avatar asked Apr 28 '14 12:04

Tom Maher


People also ask

Is a lambda expression a delegate?

Since a lambda expression is just another way of specifying a delegate, we should be able to rewrite the above sample to use a lambda expression instead of an anonymous delegate. In the preceding example, the lambda expression used is i => i % 2 == 0 . Again, it is just a convenient syntax for using delegates.

What is the difference between lambdas and delegates?

They are actually two very different things. "Delegate" is actually the name for a variable that holds a reference to a method or a lambda, and a lambda is a method without a permanent name. Lambdas are very much like other methods, except for a couple subtle differences.

What is the type of a lambda expression C#?

Lambda expressions in C# are used like anonymous functions, with the difference that in Lambda expressions you don't need to specify the type of the value that you input thus making it more flexible to use. The '=>' is the lambda operator which is used in all lambda expressions.

Which sentence about lambda statement is not true?

Which is NOT true about lambda statements? A statement lambda cannot return a value.


2 Answers

Convert isn't a method at all - it's a UnaryExpression and indeed is there exactly why you theorized - boxing / type coercion. It's interesting to see when expression trees are generated, things we generally know are implicit actually appear explicitly.

If you were building an expression yourself, you can get the same effect by calling Expression.Convert():

Creates a UnaryExpression that represents a type conversion operation.

like image 158
Rex M Avatar answered Oct 12 '22 08:10

Rex M


Yes, it is Conversion expression which represents boxing and not only boxing. It contains user defined conversions etc.

For example, If a type defines user defined conversions that will be convered using "Conversion expression". In this case weakTyped.Body.Method will return the overloaded method something like op_Implicit...

You can prove this with following code.

public static void Test<TProperty>(Expression<Func<Model, TProperty>> strongTyped, Expression<Func<Model, object>> weakTyped)
{
    var expr = (UnaryExpression)weakTyped.Body;
    Console.WriteLine("Weak Typed method: {0}", expr.Method);
    Console.WriteLine("Strong Typed: {0}", strongTyped);
    Console.WriteLine("Weak Typed: {0}", weakTyped);
}
public static void TestFloat<TProperty>(Expression<Func<Model, TProperty>> strongTyped, Expression<Func<Model, decimal>> weakTyped)
{
    var expr = (UnaryExpression) weakTyped.Body;
    Console.WriteLine("Weak Typed method: {0}", expr.Method);
    Console.WriteLine("Strong Typed: {0}", strongTyped);
    Console.WriteLine("Weak Typed: {0}", weakTyped);
}

For decimal type this returns overloaded operator where as object weakTyped.Body.Method will be null since it is just a boxing conversion.

like image 42
Sriram Sakthivel Avatar answered Oct 12 '22 09:10

Sriram Sakthivel