Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Changing the return type of an expression<func<>>

Say I have an Expression<Func<T,object>> is it possible to dynamically change the return type based on a Type variable to be something like Expression<Func<T,int>>

I have the following class:

public class ImportCheck<T> {

    public int id { get; set; }
    public string Name { get; set; }
    public Type Type { get; set; }
    public bool Required { get; set; }
    public int? MinLength { get; set; }
    public int? MaxLength { get; set; }
    public string Value { get; set; }
    public Expression<Func<T, object>> AssociatedProperty { get; set; }
}

I have a List<ImportCheck<Contact>> which I loop through and for each one set a property on the Contact object (the properties are all different types). To enable me to set the property of nested objects I need the result type to be the same as the target type. If all the properties of the contact were say int then what I have now would work fine it's the fact that I have a list of different types that is causing me the headache.

This is how I set a sub property:

private static Action<M, R> MakeSet<M, R>(Expression<Func<M, R>> fetcherExp) {
            if (fetcherExp.Body.NodeType != ExpressionType.MemberAccess) {
                throw new ArgumentException(
                    "This should be a member getter",
                    "fetcherExp");
            }

            //    Input model 
            var model = fetcherExp.Parameters[0];
            //    Input value to set 
            var value = Expression.Variable(typeof(R), "v");
            //    Member access 
            var member = fetcherExp.Body;
            //    We turn the access into an assignation to the input value 
            var assignation = Expression.Assign(member, value);
            //    We wrap the action into a lambda expression with parameters 
            var assignLambda = Expression.Lambda<Action<M, R>>(assignation, model, value);

            return assignLambda.Compile();
        }

This is then called like MakeSet(member)(target,value) where member is the Expression<Func<T,object>> target is the object and value is the value to set the property to.

like image 900
Gaz Avatar asked Jul 09 '15 21:07

Gaz


People also ask

What is the return type of the function?

The type of the expression is the return type of the function. Required. A list of statements that returns a value by using the Return statement. (See Return Statement .) The type of the value returned is the return type of the function. A lambda expression is a function without a name that calculates and returns a value.

What is the return type of a lambda expression?

A single expression. The type of the expression is the return type of the function. Required. A list of statements that returns a value by using the Return statement. (See Return Statement .) The type of the value returned is the return type of the function. A lambda expression is a function without a name that calculates and returns a value.

What is an expression in programming?

An expression is a sequence of operands and operators that can be evaluated to a single value or method or object or namespace. It can consist of literal values, method invocations, names of variables, names of methods, method parameters or types. Expression can vary from very simple to very complex.

What is the difference between expression<func<T> and Func<T>>?

Func<T> denotes a delegate that is pretty much a pointer to a method and Expression<Func<T>> denotes a tree data structure for a lambda expression. I think it explains well about when to use it.


1 Answers

Please find the example below:

public class ReturnTypeVisitor<TSource, TReturnValue> : ExpressionVisitor{

    protected override Expression VisitLambda<T>(Expression<T> node)
    {
        var delegateType = typeof(Func<,>).MakeGenericType(typeof(TSource), typeof(TReturnValue));
        return Expression.Lambda(delegateType, Visit(node.Body), node.Parameters);
    }

    protected override Expression VisitMember(MemberExpression node)
    {
        if (node.Member.DeclaringType == typeof(TSource))
        {
            return Expression.Property(Visit(node.Expression), node.Member.Name);
        }
        return base.VisitMember(node);
    }
}

Usage:

public class Foo{
    public Bar Bar { get; set; }
}

public class Bar { }

Expression<Func<Foo, object>> expression = p => p.Bar;
Expression<Func<Foo, Bar>> stronglyTypedReturnValue = (Expression<Func<Foo, Bar>>)new ReturnTypeVisitor<Foo, Bar>().Visit(expression);
like image 137
Herr Kater Avatar answered Sep 21 '22 04:09

Herr Kater