generic delegate creation using Expression in C# - c#

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:
static void Main() { Test<double>(); }
static void Test<T>()
{
Action<T> genericDel = delegate { };
// Place break-point here.
}
Now, if I try executing this delegate from within the Test method (by placing a break-point and using the immediate window) like this:
genericDel(42D);
I get the following error:
Delegate 'System.Action<T>' has some invalid arguments
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 double to T.
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:
genericDel.DynamicInvoke(42D);
(or)
((Action<double>)(object)genericDel)(42D);

The problem is that you are trying to invoke the delegate within the scope of the method that is creating it, before 'T' is known. It is trying to convert a value type (an integer) to the generic type 'T', which is not allowed by the compiler. If you think about it, it makes sense. You should only be able to pass in T as long as you are within the scope of the method that is creating the delegate, otherwise it wouldn't really be generic at all.
You need to wait for the method to return, then use the delegate. You should have no problem invoking the delegate after its completed:
var a = CreateDelegate<double>(myFieldInfo[0], tst);
var b = CreateDelegate(myFieldInfo[0], tst);
a(434);

Related

F# type error in function return value

I'm trying to implement the following code snippet in F#:
// Method style
void Callback (NSNotification notification)
{
Console.WriteLine ("Received a notification UIKeyboard", notification);
}
void Setup ()
{
NSNotificationCenter.DefaultCenter.AddObserver (UIKeyboard.WillShowNotification, Callback);
}
I have done the following:
let toggleKeyboard(notification : NSNotification) =
Console.WriteLine ("Received a notification UIKeyboard", notification)
NSNotificationCenter.DefaultCenter.AddObserver(UIKeyboard.WillShowNotification, toggleKeyboard) |> ignore
This seems like a straightforward implementation, however I get a type error:
This expression was expected to have type 'Action<NSNotification>' but here has type ''a -> unit' (FS0001) (Dissertation)
I'm not really sure how to make my method return a Action<NSNotification> type.
Sometimes F# will automatically cast functions to Action<T> or Func<T> types, but you can also explicitly wrap your function in an Action<T> like this:
let foo x = printfn "%s" x
let action = System.Action<string>(foo)
action.Invoke("hey") // prints hey
Or in your case:
...AddObserver(UIKeyboard.WillShowNotification, System.Action<NSNotification>(toggleKeyboard)) |> ignore

C# Invoke Method Console Write Demo

The code snippet below is from an ASP.NET MVC application. It accepts all parameters from browser. I believe it's vulnerable.
I'm testing an application's security, it uses Invoke method, but accepts the Object type, method and parameters dynamically from user's input. I believe it is dangerous and I'm trying to prove it.
Do you think I can invoke Console.Write or execute some sort of arbitrary/dangerous code?
I want to try to use C# Invoke Method to write to console to prove the vulnerability. This is what I did:
static void Main(string[] args)
{
Type magicType = Type.GetType("System");
ConstructorInfo magicConstructor = magicType.GetConstructor(Type.EmptyTypes);
object magicClassObject = magicConstructor.Invoke(new object[] { });
MethodInfo magicMethod = magicType.GetMethod("Console.Write");
object magicValue = magicMethod.Invoke(magicClassObject, new object[] { 100 });
}
But it doesn't work. It says Object is not initialized. What am I missing?
System is not a type, it's a namespace. You're actually looking for System.Console, which is the console class. After that, you're looking for the WriteLine method with the proper overload, which takes an int, which is what you pass to Type.GetMethod. Only then, you can invoke the MethodInfo object using Invoke passing null as the object (as this is a static class) and the right parameter.
What you actually want is this:
Type magicType = Type.GetType("System.Console");
var method = magicType.GetMethod("WriteLine", new[] { typeof(int) });
method.Invoke(null, new object[] { 100 });

Creating a Delegate from methodInfo in Mono 2.8.2

Hi I am trying to create a messenger in Mono 2.8.2 - the subset used by Unity3d. I thought it would be nifty to create a helper to auto subscribe methods to the messenger when they are decorated with a "subscribe" attribute.
I've been scratching my head over this and have read many of the other related stack questions without a solution to my problem. Frankly, I don't know if I am doing something wrong or if this is a bug in Mono.
foreach (var methodInfo in methods)
{
var attr = methodInfo.GetAttribute<SubscribeAttribute>();
if (attr == null)
continue;
var parmas = methodInfo.GetParameters();
if (parmas.Length != 1)
{
Debug.LogError("Subscription aborted. Invalid paramters.");
continue;
}
var type = parmas[0].ParameterType;
// Crashes here
// ArgumentException: method argument length mismatch
// I have tried many combinations..
// Direct typing of the message type and dynamic typing
var action = (Action<object>)Delegate.CreateDelegate(typeof(Action<object>), methodInfo);
// also does not work
// var dt = Expression.GetActionType(parmas.Select(o => o.ParameterType).ToArray());
// var action = Delegate.CreateDelegate(dt, methodInfo);
Subscribe(type, action, instance);
}
Any suggestions or work around would be appreciated.
Edit
The method signature looks like :
[Subscribe]
void OnMessage(object message){
// Hello World
}
Though, it was originally...
[Subscribe]
void OnTestMessage(TestMessage message){
// Hello World
}
It's a non-static method and you didn't provide a target object. Therefore Delegate.CreateDelegate will create an "open delegate" with an explicit this argument.
Because of the required this argument, it no longer matches the signature.

Passing a method as a parameter with zero or more parameters for the passed in method?

I'm trying to code what I've called a 'trigger'. They take an object, a function and some kind of activation criteria. Once activated, it runs the method on that object.
Here's a basic stripped down example. It works as expected for now. An example usage would be:
SomeObject myObj = new SomeObject();
MyTrigger trigger = new MyTrigger(myObj, "Delete");
trigger.Activate(); // calls myObj.Delete();
Now where I've called Invoke with null is where parameters can normally go (I think). The problem I'm having is getting the 'zero or more paramters' as a single parameter in the function declaration. I need a thrid parameter when creating MyTrigger that would be the parameters to pass during the Invoke.
Or is there an even better way to do it? I.e. Can I somehow pass the object, the function call and the parameters as a single parameter? Maybe two parameters?
You have to use delegates.
// rewrite your trigger constructor like this
class MyTrigger<TTarget>
{
public MyTrigger(TTarget target, Action<TTarget> action);
public void Activate()
{
this._action(this._target);
}
}
// now call it with or without parameters
SomeObject myObj = new SomeObject();
var trigger = new MyTrigger<SomeObject>(myObj, o => o.Delete(1234));
trigger.Activate();
You can also create a static helper class to make the creation code slightly simpler to write:
static class MyTrigger
{
public MyTrigger<TTarget> Create<TTarget>(TTarget target, Action<TTarget> action)
{
return new MyTrigger<TTarget>(target, action);
}
}
// now write the initialization code like this (you don't have to specify the type parameter anymore):
var trigger = MyTrigger.Create(myObj, o => o.Delete());
You could use the params keyword:
public Trigger(object targetObject, string methodName, params object[] parameters)
{
//"parameters" here will be an array of length 0 if no parameters were passed
}
MyTrigger trigger = new MyTrigger(myObj, "Delete"); //no parameters
MyTrigger trigger = new MyTrigger(myObj, "Delete", param1); //one parameter
MyTrigger trigger = new MyTrigger(myObj, "Delete", param1, param2); //two parameters
But I prefer Knagis' answer because it will also provide you compile-time safety (and likely the Trigger class will be far simplified and ditch any reflection that you probably have in there.)

Create delegate dynamically from Type name

i would like to create a generic delegate but i only know the type while the execution.
here is the delegate that i want to create :
public delegate void MyDel<T>(T t,string msg);
and here is the method in which i want to instantiate and use the delegate
Type typeSet = set.GetType();
MethodInfo method = typeSet.GetMethod("Add");
Delegate test = Delegate.CreateDelegate(typeof(MyDel<typeSet>, method);
where typeSet is unknow for me at the compilation.
and unfortunately, the method that i want to call is not static.
Does anyone have any idea ?
Thanks in advance
You need to create the specific delegate type using MakeGenericType:
Type template = typeof(MyDel<>);
Type specific = template.MakeGenericType(typeSet);
Delegate test = Delegate.CreateDelegate(specific, method);
I think that's what you're after...

Categories

Resources