I am working on a function that takes a delegate type and a delegate of type Action<Object[]> and creates a dynamic function of the given type, that passes, if called, all arguments to the given action handle:
public static T GetEventDelegate<T>(Action<Object[]> handler) where T : class
{
if (!typeof(T).IsSubclassOf(typeof(Delegate)))
throw new Exception("T must be a delegate type");
Type[] argTypes = typeof(T).GetMethod("Invoke").GetParameters().Select((para) => para.ParameterType).ToArray();
List<ParameterExpression> lstArgs = new List<ParameterExpression>(
argTypes.Select((arg)=>Expression.Parameter(arg))
);
ParameterExpression result = Expression.Variable(typeof(Object[]));
var assignExpression = Expression.NewArrayInit(typeof(Object),lstArgs.ToArray());
var callExpression = Expression.Call(handler.Method, result);
var block = Expression.Block(
new List<ParameterExpression>(){result},
new Expression[]{assignExpression,callExpression}
);
var del = Expression.Lambda(block, lstArgs.ToArray()).Compile();
return Delegate.CreateDelegate(typeof(T), del, "Invoke") as T;
}
private static void testDel()
{
var del = GetEventDelegate<EventHandler>(
(x) =>
{
//Error, because x == null
Debug.Print(x.ToString());
}
);
del("testString", new EventArgs());
}
Unfortunately the action handler only gets a null value passed (see testDel()).
Could you please help me to find the error?
Thanks in advance!
Your problem is because you initialize the result ParameterExpression as type Object, but never actually assign it a value. What this pretty much compiles down to (after calling compile) is:
void Func(arguments..)
{
Object result;
new object[](arguments...);
method(result);
}
You never actually assign the array to the result with an assign expression.
Unrelated to your problem, you could use Expression.Lambda() when creating the lambda because you have the type from the generic.
Related
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.
I have the following problem
private int GetInt(dynamic a)
{
return 1;
}
private void UsingVar()
{
dynamic a = 5;
var x = GetInt(a);
}
But x is still dynamic.
I don't understand why.
Since your argument a in the GetInt method call have the type dynamic, so the overload resolution occurs at run time instead of at compile time.
Based on this:
Overload resolution occurs at run time instead of at compile time if one or more of the arguments in a method call have the type dynamic, or if the receiver of the method call is of type dynamic.
Actually by using the dynamic you are using the late binding (defers to later), and it means, the compiler can't verify it because it won't use any static type analysis anymore.
The solution would be using a cast like this:
var x = (int)GetInt(a);
The following is how the compiler is treating your code:
private void UsingVar()
{
object arg = 5;
if (<>o__2.<>p__0 == null)
{
Type typeFromHandle = typeof(C);
CSharpArgumentInfo[] array = new CSharpArgumentInfo[2];
array[0] = CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.UseCompileTimeType, null);
array[1] = CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null);
<>o__2.<>p__0 = CallSite<Func<CallSite, C, object, object>>
.Create(Microsoft.CSharp.RuntimeBinder.Binder
.InvokeMember(CSharpBinderFlags.InvokeSimpleName, "GetInt", null, typeFromHandle, array));
}
object obj = <>o__2.<>p__0.Target(<>o__2.<>p__0, this, arg);
}
UPDATE: This question was marked as duplicated, but although I understand the issue with the code, I don't have a solution. Is it possible for the code to work by only changing the method bodies and not the method signatures?
I'm tying to wrap my head around Expression and Func, while trying to build a class like the following:
public class Test<TBase>
{
private IList<Expression<Func<object, object>>> _expressions = new List<Expression<Func<object, object>>>();
public void AddExpression<T>(Expression<Func<TBase, T>> e)
{
_expressions.Add(e);
}
public void AddExpression<T1, T2>(Expression<Func<T1, T2>> e)
{
_expressions.Add(e);
}
}
I need/would like to keep a list of expressions, where the types inside the Func may vary. I though the code above would work but it doesn't. It fails with:
Cannot convert from 'Expression<Func<TBase, T>>' to 'Expression<Func<object, object>>'
Cannot convert from 'Expression<Func<T1, T2>>' to 'Expression<Func<object, object>>'
Resharper says:
Argument type 'Expression<Func<TBase, T>>' is not assignable to parameter type 'Expression<Func<object, object>>'
Argument type 'Expression<Func<T1, T2>>' is not assignable to parameter type 'Expression<Func<object, object>>'
Is it possible for the code to work by only changing the method bodies and not the method signatures?
UPDATE: This question was marked as duplicated, but although I understand the issue with the code, I don't have a solution. Is it possible for the code to work by only changing the method bodies and not the method signatures?
Yes, you can keep the method signatures, but you'll have to rewrite the expressions...
Like this:
public void AddExpression<T1, T2>(Expression<Func<T1, T2>> e)
{
var originalParameter = e.Parameters[0];
// object par1
var parameter = Expression.Parameter(typeof(object), originalParameter.Name);
// T1 var1
var variable = Expression.Variable(typeof(T1), "var1");
// (T1)par1
var cast1 = Expression.Convert(parameter, typeof(T1));
// var1 = (T1)par1;
var assign1 = Expression.Assign(variable, cast1);
// The original body of the expression, with originalParameter replaced with var1
var body = new SimpleParameterReplacer(originalParameter, variable).Visit(e.Body);
// (object)body (a cast to object, necessary in the case T2 is a value type. If it is a reference type it isn't necessary)
var cast2 = Expression.Convert(body, typeof(object));
// T1 var2; var1 = (T1)par1; (object)body;
// (the return statement is implicit)
var block = Expression.Block(new[] { variable }, assign1, cast2);
var e2 = Expression.Lambda<Func<object, object>>(block, parameter);
_expressions.Add(e2);
}
I'm using the SimpleParameterReplacer from another response I gave some time ago.
In the end a (T1 x) => x.Something (with x.Something being a T2) is transformed in:
(object x) =>
{
var var1 = (T1)x;
return (object)var1.Something;
}
I am trying to build an expression that will call a method with an out parameter. So far I've had success, except when it comes to nullable versions of the parameters.
For this purpose lets suppose the int.TryParse(string, out int) method. I've successfully been able to build an expression (no nullables) by defining a delegate type for this purpose:
internal delegate bool TestDelegate(string input, out int value);
public static MethodInfo GetMethod()
{
return typeof(int).GetMethod("TryParse", BindingFlags.Public | BindingFlags.Static, null, new[] { typeof(string), typeof(int).MakeByRefType() }, null);
}
public static void NormalTestExpression()
{
var method = GetMethod();
var pValue = Expression.Parameter(typeof(string), "str");
var pOutput = Expression.Parameter(typeof(int).MakeByRefType(), "value");
var call = Expression.Call(method, pValue, pOutput);
var lamd = Expression.Lambda<TestDelegate>(call, pValue, pOutput);
var func = lamd.Compile();
int output;
var result = func("3", out output);
// THIS WORKS!!!
}
I am trying to make this work with nullable types. Take for example:
internal delegate bool TestNullableDelegate(string input, out int? value);
The below will fail with an Argument Exception (GetMethod() is retrieving the correct method based off of the primitive type--same method from above)
public static void WithNullableTypeFails()
{
var method = GetMethod();
var pValue = Expression.Parameter(typeof(string), "str");
var pOutput = Expression.Parameter(typeof(int?).MakeByRefType(), "value");
value
var call = Expression.Call(method, pValue, pOutput); //Argument Exception int.TryParse() doesn't accept int? argument
var lamd = Expression.Lambda<TestNullableDelegate>(call, pValue, pOutput);
var func = lamd.Compile();
}
Expression of type 'System.Nullable`1[System.Int32]' cannot be used for parameter of type 'System.Int32' of method 'Boolean TryParse(System.String, Int32 ByRef)'
Now I am aware that this is because I am still invoking the MethodInfo which is taking the primitive int type and the delegates aren't matching. So I tried the below:
public static void WithNullableTypeAttempt()
{
var method = GetMethod();
var pValue = Expression.Parameter(typeof(string), "str");
var pOutput = Expression.Parameter(typeof(int?).MakeByRefType(), "value");
var vars = Expression.Variable(typeof(int), "tmp");
var resultvar = Expression.Variable(typeof(bool), "result");
var call = Expression.Call(method, pValue, vars);
var block = Expression.Block(
Expression.Assign(vars, Expression.Constant(default(int))),
Expression.Assign(resultvar, call),
Expression.Assign(pOutput, Expression.Convert(vars, typeof(int?))),
resultvar
);
var lamd = Expression.Lambda<TestNullableDelegate>(block, pValue, pOutput);
var func = lamd.Compile(); // Invalid Operation Exception
}
I get an invalid operation exception when I attempt to compile it:
variable 'tmp' of type 'System.Int32' referenced from scope '', but it is not defined
When I open the expression in one of the expression tree visualizers I have, I see the following:
(valueToParse, value) =>
{
var tmp = 0;
var result = int.TryParse(valueToParse, out tmp);
var value = (int?)tmp;
return result;
}
So I think I am on the right track.
How can I call this method where the types vary only by the Nullable type, keeping the delegate with the Nullable type?
You are currently using an overload of the method that does not support variables.
Quoting from the reference above:
Creates a BlockExpression that contains four expressions and has no variables.
You need to tell the block expression about the variables by using an overload that supports variables like this:
var block = Expression.Block(
new ParameterExpression[] { vars, resultvar }, //variables
Expression.Assign(vars, Expression.Constant(default(int))),
Expression.Assign(resultvar, call),
Expression.Assign(pOutput, Expression.Convert(vars, typeof(int?))),
resultvar);
I want to define a Lambda Expression with an out parameter. Is it possible to do it?
Below are code snippets from a C# .Net 4.0 console app that I tried.
As you can see in Procedure25 I can use lambda expressions to define a delegate that has an output parameter, however, when I want to use linq expressions to do the same, the code in procedure 24 fails with:
System.ArgumentException was unhandled Message=ParameterExpression
of type 'System.Boolean' cannot be used for delegate parameter of type
'System.Boolean&' Source=System.Core
I know I could use an input class object with a bool member and pass back the value to the caller that way but I was curious if I could somehow define out parameters.
Thanks
static void Main(string[] args)
{
Procedure25();
Procedure24();
Console.WriteLine("Done!");
Console.ReadKey();
}
private delegate int Evaluate(string value, out bool usesVars);
private static void Procedure24()
{
// This fails to compile:
//Expression<Evaluate> x = (string val, out bool usesSimVals) =>
//{
// usesSimVals = true;
// Console.WriteLine(val);
// return 1;
//};
ParameterExpression valueParameter = Expression.Parameter(typeof (string));
MethodCallExpression methodCall = Expression.Call(typeof(Console).GetMethod("WriteLine", new Type[] { typeof(object) }), valueParameter);
bool usesVars;
ParameterExpression usesVarsParameter = Expression.Parameter(typeof (bool), "out usesVars");
Expression.Lambda<Evaluate>(methodCall, valueParameter, usesVarsParameter).Compile()("test", out usesVars);
Console.WriteLine(usesVars);
}
private static void Procedure25()
{
Evaluate x = (string value, out bool vars) => { vars = true;
Console.WriteLine(value);
return 1;
};
bool usesVars;
x("test", out usesVars);
}
EDIT:
Ani, awesome, thanks. So the key thing was to call MakeByRefType on the parameter type.
For the record here is a code snippet that works based on Ani's suggestion:
private static void Procedure24()
{
ParameterExpression valueParameter = Expression.Parameter(typeof (string));
MethodCallExpression methodCall = Expression.Call(typeof(Console).GetMethod("WriteLine", new Type[] { typeof(object) }), valueParameter);
bool usesVars;
ParameterExpression usesVarsParameter = Expression.Parameter(typeof (bool).MakeByRefType(), "out usesVars");
Expression block = Expression.Block(methodCall, Expression.Assign(usesVarsParameter, Expression.Constant(true)), Expression.Constant(1));
int result = Expression.Lambda<Evaluate>(block, valueParameter, usesVarsParameter).Compile()("test", out usesVars);
Console.WriteLine("Result={0}, usesVars={1}", result, usesVars);
}
You need Type.MakeByRefType:
var usesVarsParameter = Expression.Parameter(typeof(bool).MakeByRefType(), "usesVars");
Note that your code sample has an additional problem: your expression-body isn't correct - it's not returning a value when it should be returning an int to satisfy the delegate-type's return-type.
Here's a way you can fix that (like your lambda example):
var body = Expression.Block(methodCall, Expression.Constant(1));
Expression.Lambda<Evaluate>(body, valueParameter, usesVarsParameter)
.Compile()("test", out usesVars);
Also note that you are not assigning the out parameter inside the expression. Expression.Lambda is letting you get away with it, which I didn't expect, but hey, the BCL doesn't have to follow the same rules as C#!