Explicit conversion of parameters in Expression Trees created from MethodInfo - c#

I have the method below which converts a (non-static) MethodInfo into a compiled Expression (Func) which I can then call.
This works great: I can call it with a method expecting both reference objects and value types.
BUT unlike the original method where I could call a method that had a parameter expecting a double and pass it an int this compiled expression doesn't support that and throws an InvalidCastException.
How do I modify this to support the same type of implicit casting that happens during a normal method call?
Bonus question: should the instanceExp use the DeclaringType or the ReflectedType from the MethodInfo?
public Func<object, object[], object> Create(MethodInfo methodInfo)
{
var methodParams = methodInfo.GetParameters();
var arrayParameter = Expression.Parameter(typeof(object[]), "array");
var arguments =
methodParams.Select((p, i) => Expression.Convert(
Expression.ArrayAccess(arrayParameter, Expression.Constant(i)), p.ParameterType))
.Cast<Expression>()
.ToList();
var instanceParameter = Expression.Parameter(typeof(object), "controller");
var instanceExp = Expression.Convert(instanceParameter, methodInfo.DeclaringType);
var callExpression = Expression.Call(instanceExp, methodInfo, arguments);
var bodyExpression = Expression.Convert(callExpression, typeof(object));
return Expression.Lambda<Func<object, object[], object>>(
bodyExpression, instanceParameter, arrayParameter)
.Compile();
}
--- EDIT
The working solution is:
var changeTypeMethod = typeof(Convert).GetMethod("ChangeType", new Type[] { typeof(object), typeof(TypeCode) });
var arguments =
methodParams.Select((p, i) =>
!typeof(IConvertible).IsAssignableFrom(p.ParameterType)
// If NOT IConvertible, don't try to convert it
? (Expression)Expression.Convert(
Expression.ArrayAccess(arrayParameter, Expression.Constant(i)), p.ParameterType)
:
// Otherwise add an explicit conversion to the correct type to handle int <--> double etc.
(Expression)Expression.Convert(
Expression.Call(changeTypeMethod,
Expression.ArrayAccess(arrayParameter, Expression.Constant(i)),
Expression.Constant(Type.GetTypeCode(p.ParameterType))),
p.ParameterType)
)
.ToList();

The problem is the same as in this piece of C# code:
object a = 123;
double b = (double)a; // InvalidCastException
The reason is that a is an object, so in order to make it a double the cast must unwrap it, and then transform an int to double. The language allows the cast to do only one thing - it will either unwrap or transform, but not both. You need to tell the compiler how to do this cast explicitly by telling it that there is an int wrapped inside the object:
double b = (double)((int)a); // Works
If you could do the same thing in your LINQ expression, your compiled expression will work as well. However, you may not know the actual type of the parameter at the time you generate your expression, so you may want to go for a different strategy - wire in a call to Convert.ChangeType method, which can unwrap and cast at the same time.

Related

Is there a way to instantiate a class via Expression.New where 'ConstructorInfo' is supplied by an ExpressionParameter?

I would like to instantiate a (non-generic) class in C# (ClassToBeInstantiated) that has a public non-parameterless constructor via LINQ Expression.New inside an Expression.Block.
see update below, based on answer from #sweeper
Description
According to the documentation, the only overloads for Expression.New that do accept arguments require a ConstructorInfo argument. As I do not have access to that info beforehand, but have to retrieve this inside the Expression.Block.
So I am able to use an Expression.Call on the type ClassToBeInstantiated that is passed into the block.
However, all Expression.New overloads only accept either ConstructorInfo as an argument or for an instantiation if I want to pass arguments to the constructor. Type is only available for using a parameterless constructor.
I cannot use a ParameterExpression holding a ConstructorInfo either.
Question
So my question: is there a way around this with Expression.New? I know I can use ConstructorInfo.Invoke via another Expression.Call. But this seems akward to me, as -at least in my opinion- the Expression.New API should exactly do this for me.
Am I missing something?
Thanks for your help, comments and reply.
The class to be instantiated
Here is some additional information to further illustrate the case:
public class ClassToBeInstantiated
{
public ClassToBeInstantiated(int count) { }
}
Helper class to retrieve ConstructorInfo
public static class GetConstructor
{
public static ConstructorInfo GetNonGenericConstructorInfo(Type type, params Type[] typeArguments) =>
type.GetConstructor(typeArguments);
}
[Test]
public void InstantiateTypeViaExpressionNew()
{
var typeExpression = Expression.Parameter(typeof(Type), "type");
var countExpression = Expression.Parameter(typeof(int), "count");
var ctorExpression = Expression.Variable(typeof(ConstructorInfo), "constructorInfo");
var block = Expression.Block
(
new[] { ctorExpression },
Expression.Assign(ctorExpression, Expression.Call(typeof(GetConstructor), nameof(GetConstructor.GetNonGenericConstructorInfo),
Type.EmptyTypes, typeExpression, Expression.Constant(new[] { countExpression.Type }))),
Expression.New(/* error - obviously does not compile: ctorInfo */, countExpression)
);
var lambda = Expression.Lambda<Func<Type, int, object>>(block, typeExpression, countExpression);
var func = lambda.Compile();
var o = func.Invoke(typeof(ClassToBeInstantiated), 4);
var instance = o as ClassToBeInstantiated;
Assert.NotNull(instance);
}
Update with Expression.Call instead of Expression.New
I updated the code example from my original question, based on the answer from #Sweeper to provide a full example (in case someone is interested):
Updated helper class
Here, I added the field constructorInfoInvokeMethodInfo for retrieval of the MethodInfo for the ConstructorInfo.Invoke() method (to be called from inside the Expression.Block:
public static class GetConstructor
{
public static ConstructorInfo GetNonGenericConstructorInfo(Type type, params Type[] typeArguments) =>
type.GetConstructor(typeArguments);
public static readonly MethodInfo constructorInfoInvokeMethodInfo =
typeof(ConstructorInfo).GetMethod(nameof(ConstructorInfo.Invoke), new[] { typeof(object[]) });
}
Updated test for Expression.Block
Here, I replaced the (non-working) Expression.New with an Expression.Call to instantiate the type via ConstructorInfo.Invoke():
[Test]
public void InstantiateTypeViaExpressionCall()
{
var typeExpression = Expression.Parameter(typeof(Type), "type");
var countExpression = Expression.Parameter(typeof(int), "count");
var ctorExpression = Expression.Variable(typeof(ConstructorInfo), "constructorInfo");
var block = Expression.Block
(
new[] { ctorExpression },
Expression.Assign
(
ctorExpression,
Expression.Call(typeof(Activator), nameof(GetNonGenericConstructorInfo), Type.EmptyTypes, typeExpression, Expression.Constant(new[] { countExpression.Type }))
),
Expression.Call(ctorExpression, constructorInfoInvokeMethodInfo, Expression.NewArrayInit(typeof(object), Expression.Convert(countExpression, typeof(object))))
);
var lambda = Expression.Lambda<Func<Type, int, object>>(block, typeExpression, countExpression);
var func = lambda.Compile();
var o = func.Invoke(typeof(ClassToBeInstantiated), 4);
var instance = o as ClassToBeInstantiated;
Assert.NotNull(instance);
}
So my question: is there a way around this with Expression.New? I know I can use ConstructorInfo.Invoke via another Expression.Call.
This is exactly what you should do.
Think about the expression tree that you want to create. Since the final usage that you want to achieve looks like:
func.Invoke(typeof(ClassToBeInstantiated), 4);
func's expression must look like:
(type, count) => GetConstructor.GetNonGenericConstructorInfo(type, typeof(int)).Invoke(new object[] {count})
This seems to be what you were trying to do too, just with an extra local variable.
It cannot be:
(type, count) => new type(count)
Because new type(count) is not a valid expression. type is just a parameter.
This has nothing to do with new expressions that Expression.New creates. There are no NewExpressions in your desired expression at all. It would be very weird if Expression.New suddenly starts inserting ConstructorInfo.Invoke calls in the expression tree, because that is not what it is supposed to create at all.
You could use Expression.New here to create expressions such as:
(type, count) => new ClassToBeInstantiated(count)
But I don't think that's what you want... You want the type parameter to determine what type to instantiate, and assume that a one-parameter int constructor to be available, right?
Using sharplab.io, you can write the lambda expression you want, and see what code the compiler actually generates for building the expression tree. After cleaning up the code that generates for
Expression<Func<Type, int, object>> func =
(type, count) => GetConstructor.GetNonGenericConstructorInfo(type, typeof(int)).Invoke(new object[] {count});
You get:
MethodInfo getConstructorMethod = typeof(GetConstructor).GetMethod(nameof(GetConstructor.GetNonGenericConstructorInfo));
MethodInfo invokeMethod = typeof(ConstructorInfo).GetMethod(nameof(ConstructorInfo.Invoke), new Type[] { typeof(object[]) });
ParameterExpression typeParam = Expression.Parameter(typeof(Type), "type");
ParameterExpression countParam = Expression.Parameter(typeof(int), "count");
// GetNonGenericConstructorInfo(type, typeof(int))
MethodCallExpression instance = Expression.Call(null, getConstructorMethod,
typeParam, Expression.NewArrayInit(typeof(Type), Expression.Constant(typeof(int), typeof(Type)))
);
// // .Invoke(new object[] { count })
MethodCallExpression body = Expression.Call(instance, invokeMethod,
Expression.NewArrayInit(typeof(object), Expression.Convert(countParam, typeof(object)))
);
Expression<Func<Type, int, object>> func = Expression.Lambda<Func<Type, int, object>>(body, typeParam, countParam);
And func.Compile()(typeof(ClassToBeInstantiated), 4) as ClassToBeInstantiated is not null.

Can I dynamically create an expression representing a lambda which calls a method on the input parameter?

Let's say I have an object of a certain class A.
Let's say I need an Expression which calls method M on class A.
Is this even doable?
Basically, I need to programatically get this lambda
a => a.M();
The trick is, I want to do this generically, i.e. I plan to use reflection to figure out that the method is called M and what parameters it wants.
I tried using Expression.Lambda(MethodCallExpression method, ParameterExpression params).
The issue there is that when I define the method call expression, I have to specify an instance (or leave it at null if it's a static method, which it isn't). I don't want this. I want whatever the parameter is passed into the lambda (a in my example) to be the instance.
Is this possible?
Yes, it's possible to construct a linq expression at a runtime.
E.g. below is an example of constructing an expression of a method call which returns an object. This is really a dummy example as it's better to avoid object in favor of strict types.
static Expression<Func<T, object>> ComposeMethodCallExpressionAsFuncObject<T>(string methodName)
{
MethodInfo mi = typeof(T).GetMethod(methodName, types: new Type[0])
?? throw new ArgumentException($"There is no '{methodName}' method in the '{typeof(T).Name}' with the empty arguments list!");
var paramExpression = Expression.Parameter(typeof(T));
var methodCallExpression = Expression.Call(paramExpression, mi);
var result = Expression.Lambda<Func<T, object>>(methodCallExpression, paramExpression);
return result; // (T obj) =>obj.methodName()
}
, and example of usage:
int foo = 9988;
var expression = ComposeMethodCallExpressionAsFuncObject<int>(nameof(int.ToString));
//expression: (int obj) => obj.ToString()
var result = expression.Compile()(foo);
Assert.AreEqual("9988", result);

Delegate.CreateDelegate to get Func<> from MethodInfo does not work for double type?

Im trying to use create a func for double.CompareTo.
Im creating it like this:
var method = typeof(double).GetMethod("CompareTo", new Type[] { typeof(double) });
var func = (Func<double, double, int>)Delegate.CreateDelegate(typeof(Func<double, double, int>), method);
It works fine for string.CompareTo like this:
var method = typeof(string).GetMethod("CompareTo", new Type[] { typeof(string) });
var func = (Func<string, string, int>)Delegate.CreateDelegate(typeof(Func<string, string, int>), method);
I get an Argument exception saying That "the target method cannot be bound to since its signature or security transparency is not compatible with the delegate type" (freely translated from Swedish)
What is wrong?
IIRC the "extend the parameters and treat the first as the target" trick only works with reference types, such as string - presumably because this instance method invoke becomes a static call with the address of the first argument, rather than simply loading the two arguments. You can hack around it - not very elegantly - via:
var dm = new DynamicMethod(nameof(double.CompareTo), typeof(int),
new[] { typeof(double), typeof(double) });
var il = dm.GetILGenerator();
il.Emit(OpCodes.Ldarga_S, 0); // load "ref arg0"
il.Emit(OpCodes.Ldarg_1); // load "arg1"
il.Emit(OpCodes.Call, method); // call CompareTo
il.Emit(OpCodes.Ret);
var func = (Func<double, double, int>)dm.CreateDelegate(
typeof(Func<double, double, int>));
Or more simply, of course (although I suspect this won't help in the general case):
Func<double, double, int> func = (x,y) => x.CompareTo(y);

How to Call a Generic Method using "Expression.Parameter" and "Expression.Call" APIs

Using the Expression Tree API I want to generate code for code that looks like this:
FieldInfo enumFieldInfo = enumFieldInfoSet.SingleOrDefault(fieldInfo => fieldInfo.Name == enumName);
I have written this code but it's not working:
var enumerableType = typeof(Enumerable);
var enumerableGenericType = typeof(IEnumerable<>).MakeGenericType(typeof(FieldInfo));
var predicateGenericType = typeof(Func<>).MakeGenericType(typeof(Func<FieldInfo, bool>));
ParameterExpression fieldInfoSource = Expression.Parameter(enumerableGenericType, "fieldInfoSource");
ParameterExpression predicateSource = Expression.Parameter(predicateGenericType, "funcPredicateOnFieldInfo");
var arrayOfTypes = new Type[] { enumerableGenericType, predicateGenericType };
MethodCallExpression SingleOrDefaultMethodCall = Expression.Call(enumerableType, "SingleOrDefault",arrayOfTypes, fieldInfoSource, predicateSource);
Here is the runtime error: No generic method 'SingleOrDefault' on type 'System.Linq.Enumerable' is compatible with the supplied type arguments and arguments. No type arguments should be provided if the method is non-generic.
I have tried a number of combinations of type coercion but still have not stumbled on the right combination. I know that the SingleOrDefault is an Extension method on the Enumerable class and that it needs two parameters; I've look at the code via the debugger and have written to code inspect its properties at run-time; what am I missing.
The problem is that you are using the Expression.Call overload which takes a type, and for a static method you need an overload with MethodInfo.
void Main()
{
Expression<Func<IEnumerable<FieldInfo>, Func<FieldInfo,bool>, FieldInfo>> singleOrDefaultExpr = (l,p) => l.SingleOrDefault(p);
var callSource = (MethodCallExpression)singleOrDefaultExpr.Body;
var method = callSource.Method;
var collectionParameter = Expression.Parameter(typeof(IEnumerable<FieldInfo>), "enumFieldInfoSet");
var enumNamePredicateParameter = Expression.Parameter(typeof(Func<FieldInfo,bool>), "enumNamePredicate");
var body = Expression.Call(method, collectionParameter, enumNamePredicateParameter);
var lambda = Expression.Lambda<Func<IEnumerable<FieldInfo>, Func<FieldInfo, bool>, FieldInfo>>(body, collectionParameter, enumNamePredicateParameter);
var f = lambda.Compile();
Console.WriteLine(f(typeof(Apple).GetFields(), fi => fi.Name == "color").Name);
}
class Apple
{
public string color;
}
Also, you can use another method to find the required MethodInfo:
var method = typeof(Enumerable)
.GetMethods()
.Single(m => m.Name == "SingleOrDefault" && m.GetParameters().Count() == 2)
.MakeGenericMethod(new[] {typeof(FieldInfo)});
UPDATE:
There is actually a simpler method, and you were on the right track, but your code had en error.
var collectionParameter = Expression.Parameter(typeof(IEnumerable<FieldInfo>), "enumFieldInfoSet");
var enumNamePredicateParameter = Expression.Parameter(typeof(Func<FieldInfo,bool>), "enumNamePredicate");
var body = Expression.Call(typeof(Enumerable), "SingleOrDefault", new[] { typeof(FieldInfo)}, collectionParameter, enumNamePredicateParameter);
var lambda = Expression.Lambda<Func<IEnumerable<FieldInfo>, Func<FieldInfo, bool>, FieldInfo>>(body, collectionParameter, enumNamePredicateParameter);
The problem was that SingleOrDefault has only one generic type parameter: 'FieldInfo' in this case:
SingleOrDefault<FieldInfo>(....
Don't mix it up with the method parameters, there are two of them:
SingleOrDefault<GenericParameter>(
this IEnumerable<GenericParameter> firstMethodParameter,
Func<GenericParameter, bool> secondMethodParameter
)
George did a great job in getting me on the right track and did provide me a partial answer; I re-fashion my code so that is was clear to me. This is an example of code that I wanted to machine generate in testing our Meta-programming runtime. I am providing more code than is necessary for the specific problem but I wanted the others to see the greater context.
// Code to Generate Enum Field Metadata ...
string enumName = Enum.GetName(theEnumType, theOrdinalEnumValue);
Array enumValues = Enum.GetValues(theEnumType);
object enumValue = enumValues.GetValue(theOrdinalEnumValue);
object enumObject = Enum.ToObject(theEnumType, theOrdinalEnumValue);
// Create Local variables of the types targeted for assignment expressions that we will make in the generated code
var enumVariables = Expression.RuntimeVariables(Expression.Variable(typeof(string), "gcEnumName"),
Expression.Variable(typeof(Array), "gcEnumValues"),
Expression.Variable(typeof(object), "gcEnumValue"),
Expression.Variable(theEnumType, "gcEnumObject"),
Expression.Variable(typeof(FieldInfo), "gcFieldInfoOnEnum"));
// Setup the Input Parameters for calls into Enum and Array Types in preperation for Assignments
ParameterExpression theInputOfEnumType = Expression.Variable(typeof(Type), "theInputOfEnumType");
ParameterExpression theEnumFieldNameValue = Expression.Variable(typeof(string), "theEnumFieldNameValue");
ParameterExpression aEnumObjectIndexValue = Expression.Variable(typeof(int), "aEnumObjectIndexValue");
ParameterExpression anArrayOfEnumObjects = Expression.Variable(typeof(Array), "anArrayOfEnumObjects");
ParameterExpression anEnumerableObject = Expression.Variable(typeof(Enumerable), "anEnumerableObject");
ParameterExpression directEnumTypeResolved = Expression.Variable(theEnumType, "directEnumTypeResolved");
ParameterExpression fieldInfoOnEnum = Expression.Variable(typeof(FieldInfo), "fieldInfoOnEnum");
var fieldInfoEnumerableRepresentation = typeof(Enumerable);
In perpetration of making calls to "Expression.Call" we need to get some MethodInfo data
// We need to generate MethodInfo on the Methods we want to call in the generated code. This is metadata
// we need to call the Expression.Call API.
MethodInfo enumGetNameMethodInfo = enumMetadata.GetMethods().FirstOrDefault(info => info.Name == "GetName");
MethodInfo enumGetValuesMethodInfo = enumMetadata.GetMethods().FirstOrDefault(info => info.Name == "GetValues");
MethodInfo enumGetValueMethodInfo = arraryMetadata.GetMethods()
.FirstOrDefault(methodInfo => (methodInfo.Name == "GetValue") && methodInfo.GetParameters().Any(param =>param.ParameterType == typeof(int)));
MethodInfo enumToObjectMethodInfo = enumMetadata.GetMethods()
.FirstOrDefault(info => info.Name == "ToObject");
// We know that there exist a number of polymorphic instances of the "SingleOrDefault" Extension method
// so we use the name of the parameter named "predicate" to locate our method. **FYI Can't use the MethodInfo data in a call to Expression.Call - It's a generic definition**.
MethodInfo enumerableSingleOrDefaultInfo = fieldInfoEnumerableRepresentation.GetMethods()
.FirstOrDefault(methodInfo => (methodInfo.Name == "SingleOrDefault") &&
methodInfo.GetParameters()
.Any(param => param.Name == "predicate"));
Here is the final code that works in making a call to a Generic Method:
// An approach to setup a Generic method call that will be used in an Expression.Assign call
// I decompose this code so for debugging purposes
// I create the "inputOfTSourceType" as a Generic Type because in the Definition of "SingleOrDefault" method there is only one Generic Parameter;
// also, take special note that in the assemblage of Expression.Call methods any of the methods that take a MethodInfo instance you can't pass in
// a "Generic" method definition. If you take a look at the code that is called it will throw and exception if it detects the IsGenericMethodDefinition
// flag is true.
var inputOfTSourceType = typeof(IEnumerable<>).MakeGenericType(typeof(FieldInfo)); // This is the type on the "source" TSource parameter
var predicateOfFuncType = typeof(Func<FieldInfo, bool>); // This is the type on the "predicate" parameter
// Take note there that we only define one(1) type here ("inputParameterType"); this is the type we wish apply to the Generic Type TSource
// declaration: public static TSource SingleOrDefault<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate);
var inputParameterType = new[] {typeof(FieldInfo)}; // This is the type we must match to "source" parameter
// The "SingleOrDefault" method can take two parameters and in this case I need to pass in a lambda expression as the predicate.
// Se we need two parameters.
ParameterExpression fieldInfoSource = Expression.Parameter(inputOfTSourceType, "fieldInfoSource"); // This is: this IEnumerable<TSource>
ParameterExpression predicateSource = Expression.Parameter(predicateOfFuncType, "funcPredicateOnFieldInfo"); // This is: Func<TSource, bool> predicate
MethodCallExpression SingleOrDefaultMethodCall =
Expression.Call(fieldInfoEnumerableRepresentation, // This is the Object Instance for which the
"SingleOrDefault", // The Name of the Generic Method
inputParameterType, // The Generic Type
fieldInfoSource, // this is the "this" source parameter
predicateSource); // this the "predicate" parameter
Expression localEnumNameAssignment =
Expression.Assign(enumVariables.Variables[0], EnumGetNameMethodCall);
Expression localEnumObjectsAssignment =
Expression.Assign(enumVariables.Variables[1], EnumGetValauesMethodCall);
Expression localEnumObjectAssignment =
Expression.Assign(enumVariables.Variables[2], ArrayGetValueMethodCall);
Expression localEnumTypeAssignment =
Expression.Assign(enumVariables.Variables[3], Expression.Convert(EnumToObjectMethodCall, theEnumType));
Expression localFieldInfoAssignment =
Expression.Assign(enumVariables.Variables[4], Expression.Convert(SingleOrDefaultMethodCall, typeof(FieldInfo)));
BlockExpression blockExpression =
Expression.Block(enumVariables,
localEnumNameAssignment,
localEnumObjectsAssignment,
localEnumObjectAssignment,
localEnumTypeAssignment,
localFieldInfoAssignment,
enumTypeToReturn);
Here's the generated code:
$gcEnumName = .Call System.Enum.GetName(
$theInputOfEnumType, $gcEnumName = (System.String)$theEnumFieldNameValue)
$gcEnumValues = .Call System.Enum.GetValues($theInputOfEnumType)
$gcEnumValue = .Call $anArrayOfEnumObjects.GetValue((System.Int32) $theOrdinalEnumValue)
$gcEnumObject = (WorkflowMessagingCommands).Call System.Enum.ToObject(
$theInputOfEnumType,
(System.Object)$theEnumInstance)
// Here is the generated code to call "SignleOrDefault"
$gcFieldInfoOnEnum = .Call System.Linq.Enumerable.SingleOrDefault(
$thisSourceType,
$predciateType)

Expression Lambda with types known at runtime

I am trying to make some Expressions where I will be using a lambda to create two methods: a selector and condition. Simplified the usage is condition(selector(data)), but the intemediate type is only known at runtime. I have the following code which works as long as the intemediate type is object, but at runtime I know the real type and would like to use that.
public static ICondition<TData> GetRelayConditionByReflection(string name, string message, string assemblyName,
string fullyQualifiedName, string conditionMethodName, string selectorMethodName) {
var asm = Assembly.LoadFrom(assemblyName);
var type = asm.GetType(fullyQualifiedName);
var selectorMi = type.GetMethod(selectorMethodName, BindingFlags.Static | BindingFlags.Public);
var conditionMi = type.GetMethod(conditionMethodName, BindingFlags.Static | BindingFlags.Public);
var tCondType = selectorMi.ReturnType;
var returnType = typeof(RelayCondition<,>);
var typeArgs = new[] { typeof(TData), tCondType };
var paramTData = Expression.Parameter(typeof(TData), "data");
var selector = Expression.Lambda<Func<TData, object>>(
Expression.Call(selectorMi, paramTData), paramTData).Compile();
var paramTCondition = Expression.Parameter(tCondType, "condition");
var condition = Expression.Lambda<Func<object, bool>>(
Expression.Call(conditionMi, paramTCondition), paramTCondition).Compile();
return (ICondition<TData>)Activator.CreateInstance(returnType.MakeGenericType(typeArgs), name, condition, message, selector);
}
Specifically, there is Expression.Lambda<Func<TData, object>> and Expression.Lambda<Func<object, bool>> where object currently only allows the intemediate type to be object.
Is it possible to create this with a type known only at runtime? I am open for other approaches for the entire problem, as long as performance isn't attrocius.
If you don't need implicit downcasting (for example declaring a Func<object> when in truth you method returns a Func<Foo>), you can use the non-generic Expression.Lambda() method. It returns a LambdaExpression, but in truth it returns a Expression<> of Func<> or of Action downcasted to LambdaExpression (Expression<> is a subclass of LambdaExpression), so:
var condition = Expression.Lambda(
Expression.Call(conditionMi, paramTCondition), paramTCondition).Compile();
now condition is a Delegate, but in truth it is a Func<> (or an Action if it had a return type void).

Categories

Resources