Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dynamically set Func<> types

Tags:

c#

types

func

is there any way to set Func<> type arguments dynamically, so i don't have to use endless if statements?

Something like:

Type t = Type.GetType("System.Decimal");
Func<t> foo = new Func<t>(some_function);

Instead of:

Func<Decimal> foo = new Func<Decimal>(some_function);

UPDATE:

Here's a snippet from my code:

Type t = typeof(StavkaDokumenta).GetProperty(pd.Polje).PropertyType;
ParameterExpression pe = Expression.Parameter(typeof(StavkaDokumenta), "stavka");
Expression expr = Expressions.ResolveCompleteExpression(pe, pd.Expression);
Expression final = Expression.Convert(expr, t);
if (t == typeof(decimal))
{
    var lambda = Expression.Lambda<Func<StavkaDokumenta, decimal>>(final, pe);
    o = lambda.Compile().Invoke(stavka);
}
if (t == typeof(decimal?))
{
    var lambda = Expression.Lambda<Func<StavkaDokumenta, decimal?>>(final, pe);
    o = lambda.Compile().Invoke(stavka);
}
else if (t == typeof(int))
{
    var lambda = Expression.Lambda<Func<StavkaDokumenta, int>>(final, pe);
    o = lambda.Compile().Invoke(stavka);
}
else if (t == typeof(int?))
{
    var lambda = Expression.Lambda<Func<StavkaDokumenta, int?>>(final, pe);
    o = lambda.Compile().Invoke(stavka);
}
else if (t == typeof(string))
{
    var lambda = Expression.Lambda<Func<string>>(final, null);
    o = lambda.Compile().Invoke();
}

pd.Polje is string - name of a property inside "StavkaDokumenta" class. pd.Expression is string expression that must evaluate to type of Polje. stavka is an instance of StavkaDokumenta.

like image 698
Milos Mijatovic Avatar asked Apr 16 '12 14:04

Milos Mijatovic


1 Answers

Now that you showed what you really want, the answer is much more simple: As you are apparently only interested in the return value of that expression, you could change your code to this:

Type t = typeof(StavkaDokumenta).GetProperty(pd.Polje).PropertyType;
ParameterExpression pe = Expression.Parameter(typeof(StavkaDokumenta), "stavka");
Expression expr = Expressions.ResolveCompleteExpression(pe, pd.Expression);
Expression final = Expression.Convert(expr, t);

if (t == typeof(string))
{
    var lambda = Expression.Lambda<Func<string>>(final, null);
    o = lambda.Compile().Invoke();
}
else
{
    var lambda = Expression.Lambda(final, pe);
    o = lambda.Compile().DynamicInvoke(stavka);
}

Old answer:

You can use generics and implicit conversion to Func<T> to achieve this:

Func<T> GetFunc<T>(Func<T> func)
{
    return func;
}

Call it with a method group like so:

var foo = GetFunc(SomeMethod);

This assumes that SomeMethod looks like this:

decimal SomeMethod()
{
    // ...
}

foo will be of type Func<decimal>. If the return type of SomeMethod would be a string, the type of foo would be Func<string>.


What happens in this code is the following:

The parameter that is passed to GetFunc is a so-called "method group" and not a variable of type Func<T>. However, there exists an implicit conversion from a method group to a variable of Func<T>:

Func<decimal> func = SomeMethod; // an implicit conversion happens here

That implicit conversion is exactly what is happening here: Before GetFunc is even called, the method group SomeMethod is converted the a variable of type Func<T>. The concrete type used for T is additionally inferred by the compiler based on the return type of the method SomeMethod().
Our goal was to create an instance of Func<T> based on our method group. And because that already happens in the conversion of the parameter before the method is even called, we simply return that created instance from the method.

like image 189
Daniel Hilgarth Avatar answered Sep 27 '22 20:09

Daniel Hilgarth