Given below are two methods which create a delegate to set a field in a class. One method uses generics and the other does not.
Both the methods return a delegate and they work fine. But if I try to use the delegate that has been created inside the CreateDelegate method, then the non-generic delegate ‘del’ works fine. I can place a breakpoint on the return statement and invoke the delegate by writting del(222). But If I try to invoke the generic delegate ‘genericDel’ by writting genericDel(434), it throws an exception:
Delegate ‘System.Action’ has some invalid arguments
Can anyone explain this quirk.
class test
{
public double fld = 0;
}
public static void Main(string[] args)
{
test tst = new test() { fld = 11 };
Type myType = typeof(test);
// Get the type and fields of FieldInfoClass.
FieldInfo[] myFieldInfo = myType.GetFields(BindingFlags.Instance | BindingFlags.Public);
var a = CreateDelegate<double>(myFieldInfo[0], tst);
var b = CreateDelegate(myFieldInfo[0], tst);
Console.WriteLine(tst.fld);
b(5.0);
Console.WriteLine(tst.fld);
a(6.0);
Console.WriteLine(tst.fld);
}
public static Action<T> CreateDelegate<T>(FieldInfo fieldInfo, object instance)
{
ParameterExpression numParam = Expression.Parameter(typeof(T), "num");
Expression a = Expression.Field(Expression.Constant(instance), fieldInfo);
BinaryExpression assExp = Expression.Assign(a, numParam);
Expression<Action<T>> expTree =
Expression.Lambda<Action<T>>(assExp,
new ParameterExpression[] { numParam });
Action<T> genericDel = expTree.Compile();
//try to invoke the delegate from immediate window by placing a breakpoint on the return below: genericDel(323)
return genericDel;
}
public static Action<double> CreateDelegate(FieldInfo fieldInfo, object instance)
{
ParameterExpression numParam = Expression.Parameter(typeof(double), "num");
Expression a = Expression.Field(Expression.Constant(instance), fieldInfo);
BinaryExpression assExp = Expression.Assign(a, numParam);
Expression<Action<double>> expTree =
Expression.Lambda<Action<double>>(assExp,
new ParameterExpression[] { numParam });
Action<double> del = expTree.Compile();
//try to invoke the delegate from immediate window by placing a breakpoint on the return below: del(977)
return del;
}
I think I understood the issue; you are having problems invoking a generic delegate from the immediate window when the compile-time type of the delegate is an open generic type.
Here’s a simpler repro:
Now, if I try executing this delegate from within the
Testmethod (by placing a break-point and using the immediate window) like this:I get the following error:
Note that this not an exception like you have stated, but rather the ‘immediate window version’ of compile-time error CS1594.
Note that such a call would have failed equally at compile-time because there is no implicit or explicit conversion from
doubletoT.This is debatably a shortcoming of the immediate window (it doesn’t appear to be willing to use additional ‘run-time knowledge’ to help you out in this case), but one could argue that it is reasonable behaviour since an equivalent call made at compile-time (in source code) would also have been illegal. This does appear to be a corner case though; the immediate window is perfectly capable of assigning generic variables and executing other code that would have been illegal at compile-time. Perhaps Roslyn will make things much more consistent.
If you wish, you can work around this like so:
(or)