When i call CreateDelegate(delegateType) i get a System.ArgumentException, which according to MSDN is because the delegateType has the wrong number of parameters or the wrong parameter types.
The strange part is the code I'm using is almost all copied from MSDN. My function as whole:
public static void AssertRaisesEvent(Action action, object obj, string eventName, NumberOfTimes numberOfTimesRaised)
{
eventCounter = 0;
EventInfo eventInfo = obj.GetType().GetEvent(eventName);
Type tDelegate = eventInfo.EventHandlerType;
Type returnType = GetDelegateReturnType(tDelegate);
if (returnType != typeof(void))
throw new ApplicationException("Delegate has a return type.");
var handler =
new DynamicMethod("CompletedHandler",
typeof(int),
GetDelegateParameterTypes(tDelegate),
obj.GetType());
// Generate a method body. This method loads a string, calls
// the Show method overload that takes a string, pops the
// return value off the stack (because the handler has no
// return type), and returns.
//
ILGenerator ilgen = handler.GetILGenerator();
FieldInfo counterFieldInfo = typeof (AssertionHelpers).GetField("eventCounter",
BindingFlags.NonPublic | BindingFlags.Static);
ilgen.Emit(OpCodes.Ldfld, counterFieldInfo);
ilgen.Emit(OpCodes.Ldc_I4, 1);
ilgen.Emit(OpCodes.Add);
ilgen.Emit(OpCodes.Pop);
ilgen.Emit(OpCodes.Ret);
// Complete the dynamic method by calling its CreateDelegate
// method. Use the "add" accessor to add the delegate to
// the invocation list for the event.
//
var delParams = GetDelegateParameterTypes(tDelegate);
var handlerParams = handler.GetParameters();
Delegate dEmitted = handler.CreateDelegate(tDelegate);
eventInfo.GetAddMethod().Invoke(obj, new Object[] { dEmitted });
...
As you can see the comments are even there. As you also can see i have delParams and handlerParams variables which have the same number of parameters of the same type.
What is going on here?
MSDN: http://msdn.microsoft.com/en-us/library/ms228976.aspx
EDIT:
The event im trying to bind to:
private NullTransaction transaction;
public delegate void CompletedEventHandler(object testParam);
internal class NullTransaction : ITransaction
{
public event CompletedEventHandler Completed;
public void Dispose()
{
// no implementation
}
public void Complete()
{
// no implementation
if(Completed != null)
Completed.Invoke(this);
}
}
Most events don't return anything - in fact you assert that it has no return-type. You then declare your custom method (handler) as returning int, and try to bind it to a delegate that doesn't return an int. This won't work.
Also; your stack isn't valid for returning an int, since you "pop" the result.
i.e. I created a test with
public event EventHandler SomeEvent;
and bound to it; so then here:
Delegate dEmitted = handler.CreateDelegate(tDelegate);
you'll find that tDelegate is EventHandler. That doesn't match handler, which returns int.
Re the stack (comments); consider:
ilgen.Emit(OpCodes.Ldfld, counterFieldInfo); <=== should be ldsfld, by the way
ilgen.Emit(OpCodes.Ldc_I4, 1); // stack is now [counter] [1]
ilgen.Emit(OpCodes.Add); // stack is now [counter + 1]
ilgen.Emit(OpCodes.Pop); // stack is now empty
ilgen.Emit(OpCodes.Ret); // return
You've loaded two values, added them up, thrown the result away, and then returned. But you haven't returned the int that you claim to - this will fail IL inspection.
If you change:
var handler =
new DynamicMethod("CompletedHandler",
null,
GetDelegateParameterTypes(tDelegate),
obj.GetType());
and:
ilgen.Emit(OpCodes.Ldsfld, counterFieldInfo);
ilgen.Emit(OpCodes.Ldc_I4_1);
ilgen.Emit(OpCodes.Add);
ilgen.Emit(OpCodes.Stsfld, counterFieldInfo);
ilgen.Emit(OpCodes.Ret);
then it might work as you intend.
Also; this is simpler:
Delegate dEmitted = handler.CreateDelegate(tDelegate);
eventInfo.AddEventHandler(obj, dEmitted);
Related
I need to attach this handler to a RadListView Column creation, by adding a DataSource to the control.
public void GenericColumnCreatingHandler<T>(object sender, ListViewColumnCreatingEventArgs e)
{
e.Column.Visible = BaseEntity<int>.MemberVisibility<T>
(e.Column.FieldName, TelerikPropertyVisibilityAttribute.VisibilityTypeEnum.BaseDetails);
e.Column.HeaderText = CaricaTestoLocale(e.Column.HeaderText, "Col_" + e.Column.HeaderText);
e.Column.BestFit();
e.Column.AutoSizeMode = ListViewBestFitColumnMode.AllCells;
}
My problem is that I need to perform the handler attach from this other generic method:
private void PopulateRecord(TipoTabellaBase tipo)
{
Type generic = typeof(CommonTableService<>);
Type[] typeArgs = { tipo.Tipo };
var constructed = generic.MakeGenericType(typeArgs);
var instance = Activator.CreateInstance(constructed);
if (instance == null)
return;
MethodInfo getEntities = constructed.GetMethod("GetEntitiesWithNoParameters");
//getEntities = getEntities.MakeGenericMethod(typeArgs);
var result = (IEnumerable<BaseEntity<int>>)getEntities.Invoke(instance, null);
lvRecords.ColumnCreating += base.GenericColumnCreatingHandler<BaseEntity<int>>;
lvRecords.DataSource = result;
BestFit(lvRecords);
generic = null;
typeArgs = null;
constructed = null;
getEntities = null;
instance = null;
}
The problematic row is this one:
lvRecords.ColumnCreating += base.GenericColumnCreatingHandler<BaseEntity<int>>
because BaseEntity is EF base type for all Entities, but this is not enought for the BaseEntity.MemberVisibility method; this method need to know the exact entity type to set the visible properties (and, of course, grid column) based on specific custom attribute on that.
Question is: how I can call base.GenericColumnCreatingHandler where T is TipoTabellaBase tipo.Tipo (type) without knowing type at design time?
Any help would be very appreciated!
Thanks is advance.
Daniel
Please note that this solution is untested.
You will have to instantiate the strongly-typed version of base.GenericColumnCreatingHandler<T> at runtime.
From your code, I figure you already know how to obtain a MethodInfo instance for a given method. You will need to get the MethodInfo for base.GenericColumnCreatingHandler<T> (let's call it genericMethodInfo).
Then, you can create a strongly-typed version of that method with MakeGenericMethod:
MethodInfo typedMethodInfo = genericMethodInfo.MakeGenericMethod(new[] {
typeof(BaseEntity<int>)
});
Once that is done, you need to invoke CreateDelegate to obtain something that you can assign to the ColumnCreating event, as described here or here:
lvRecords.ColumnCreating +=
(ListViewColumnCreatingEventHandler)typedMethodInfo.CreateDelegate(
typeof(ListViewColumnCreatingEventHandler), this);
EDIT: Replaced base with this in the last code sample. In case an inherited method is specifically required, this has to be taken care of while retrieving genericMethodInfo.
I have following constructor in my class, which initializes my task:
public ReportGeneratorThread(Func<int, bool> getPermission, Action<object> a)
{
this.action = a;
this.t = new Task(this.action = this.InvokedAction, this.cancellationToken);
this.getPermission = getPermission;
}
The InvokedAction method, which will be invoked by the task is defined such as:
private void InvokedAction(object obj)
{
Debug.WriteLine(DateTime.Now.ToLongTimeString() + " Task " + this.t.Id + " has STARTED Generating a report");
this.GenerateReport();
throw new ArgumentException("For testing purpose");
}
The problem occurs when I want to invoke this method with an int rather than an object, since this is not accepted by the task. Is there any approach of how I can invoke this method with an int value with an:
Action<int>
Since you can't call Action<int> with argument of type object you need to convert it manually. Note that it would be fine if requirement is other way around - you can easily pass Action<object> where Action<int> is expected.
... new Task( v => intAction((int)v),...
You may need to handle cast exceptions if you can't guarantee that argument is always integer.
Can you box your int before invoking?
int i = 123;
object o = i;
is it possible to generate an eventhandler while running?
I want to do something like that:
public bool addCallback(string name, Delegate Callback)
{
EventInfo ei = DataProxy.GetType().GetEvent(name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
if (ei == null)
return false;
ei.AddEventHandler(DataProxy, Callback);
//now I want to add an Eventhandler, which removes the Callback and this new Eventhandler itsself
return true;
}
(I am not 100% sure I understand what you are going to hook your generated event handler to from the example, but here's the easiest way I know of for creating an event handler)
Depends on your platform and trust level. The most flexible way of doing it is to use Emit to generate the method (see here).
However, I found a relatively easy to use and good alternative to be generated Linq expressions (here's the namespace help).
The idea is fairly simple:
Use the various Expression-derived classes you can see in the namespace to define what your callback is doing. In this case, you want to generate something that calls .RemoveEventHandler (I am guessing) on the ei instance (specifically, you will use the ConstantExpression to create a ref to your ei variable and to your Callback parameter and a MethodCallExpression to create a call to the RemoveDataHandler method).
Once you create the expression that does what you need, you need to create a delegate (Lambda) out of it (see here)
Almost done. You still need to compile the lambda, which you do by calling .Compile on the object you got from the previous step (see here)
Edit: This is a Windows console example of a dynamically generated delegate that removes itself. Note that WP7 Linq expression support is more limited than .NET 4.0 and so you will need to adjust it (make helper methods that will do some of the work and call them from the expression instead of what I did).
Edit2: BTW: The mechanism by which the lambda can remove itself, is to create another lambda that returns a local variable that is of that type. After creating the lambda, save it to the local variable and run the code (I am not sure if this would have worked without the secondary lambda)
Edit3: No - you have to use the delegate trick, otherwise, the constant gets "frozen" and will not update as you would want it to. So the code as is works.
public class MyEventArgs : EventArgs
{
}
public class EventContainer
{
public event EventHandler<MyEventArgs> MyEvent;
public void Fire()
{
Console.WriteLine("Firing");
if (MyEvent != null)
{
MyEvent(this, new MyEventArgs());
}
Console.WriteLine("Fired");
}
}
class Program
{
static void Main(string[] args)
{
EventContainer container = new EventContainer();
var adder = container.GetType().GetMethod("add_MyEvent");
var remover = container.GetType().GetMethod("remove_MyEvent");
object self = null;
Func<object> getSelf = () => self;
var block = Expression.Block(
// Call something to output to console.
Expression.Call(
null,
typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }),
Expression.Constant("Event called")),
// Now call the remove_Event method.
Expression.Call(
Expression.Constant(container), // passing the container as "this"
remover, // And the remover as the method info
Expression.Convert( // we need to cast the result of getSelf to the correct type to pass as an argument
Expression.Invoke( // For the parameter (what to convert), we need to call getSelf
Expression.Constant(getSelf)), // So this is a ref to getSelf
adder.GetParameters()[0].ParameterType) // finally, say what to convert to.
)
);
// Create a lambda of the correct type.
var lambda = Expression.Lambda(
adder.GetParameters()[0].ParameterType,
block,
Expression.Parameter(typeof(object)),
Expression.Parameter(typeof(MyEventArgs)));
var del = lambda.Compile();
// Make sure "self" knows what the delegate is (so our generated code can remove it)
self = del;
// Add the event.
adder.Invoke(container, new object[] { del });
// Fire once - see that delegate is being called.
container.Fire();
// Fire twice - see that the delegate was removed.
container.Fire();
}
}
public static bool addCallback(string name, Delegate Callback)
{
if (DataProxy == null)
GetDataProxy();
EventInfo ei = DataProxy.GetType().GetEvent(name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
if (ei == null)
return false;
ei.AddEventHandler(DataProxy, Callback);
Type handlerType = ei.EventHandlerType;
MethodInfo invokeMethod = handlerType.GetMethod("Invoke");
ParameterInfo[] parms = invokeMethod.GetParameters();
Type[] parmTypes = new Type[parms.Length];
for (int i = 0; i < parms.Length; i++)
{
parmTypes[i] = parms[i].ParameterType;
}
List<ParameterExpression> parameters = new List<ParameterExpression>();
foreach(Type t in parmTypes)
{
parameters.Add(System.Linq.Expressions.Expression.Parameter(t));
}
ConstantExpression eventInfo = System.Linq.Expressions.Expression.Constant(ei, typeof(EventInfo));
ConstantExpression eventCallback = System.Linq.Expressions.Expression.Constant(Callback, typeof(Delegate));
ConstantExpression dataProxy = System.Linq.Expressions.Expression.Constant(DataProxy, typeof(MAServiceClient));
MethodCallExpression call = System.Linq.Expressions.Expression.Call(eventInfo, ei.GetType().GetMethod("RemoveEventHandler"), dataProxy, eventCallback);
//add to Expression.Body the call, which removes the new Eventhandler itsself
ei.AddEventHandler(DataProxy, System.Linq.Expressions.Expression.Lambda(ei.EventHandlerType, call, parameters).Compile());
return true;
}
This is what my method looks like right now. There is just one step missing, where the new Eventhandler (created by System.Linq.Expressions.Expression.Lambda(ei.EventHandlerType, call, parameters).Compile()) removes itsself (see comment).
Thanks to Shahar Prish I came up with the following code:
using ex = System.Linq.Expressions;
using System.Linq.Expressions;
public static bool addCallback(string name, Delegate Callback)
{
if (DataProxy == null)
GetDataProxy();
EventInfo ei = DataProxy.GetType().GetEvent(name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
if (ei == null)
return false;
ei.AddEventHandler(DataProxy, Callback);
Type handlerType = ei.EventHandlerType;
MethodInfo removeMethod = ei.GetType().GetMethod("RemoveEventHandler");
MethodInfo invokeMethod = handlerType.GetMethod("Invoke");
ParameterInfo[] parms = invokeMethod.GetParameters();
Type[] parmTypes = new Type[parms.Length];
for (int i = 0; i < parms.Length; i++)
{
parmTypes[i] = parms[i].ParameterType;
}
List<ParameterExpression> parameters = new List<ParameterExpression>();
foreach(Type t in parmTypes)
{
parameters.Add(System.Linq.Expressions.Expression.Parameter(t));
}
Delegate self = null;
Func<Delegate> getSelf = () => self;
ConstantExpression eventInfo = ex.Expression.Constant(ei, typeof(EventInfo));
ConstantExpression eventCallback = ex.Expression.Constant(Callback, typeof(Delegate));
ConstantExpression dataProxy = ex.Expression.Constant(DataProxy, typeof(MAServiceClient));
MethodCallExpression removeCallback = ex.Expression.Call(eventInfo, removeMethod, dataProxy, eventCallback);
MethodCallExpression removeSelf = ex.Expression.Call(eventInfo, removeMethod, dataProxy, ex.Expression.Invoke(ex.Expression.Constant(getSelf)));
BlockExpression block = ex.Expression.Block(removeCallback, removeSelf);
LambdaExpression lambda = ex.Expression.Lambda(ei.EventHandlerType, block, parameters);
Delegate del = lambda.Compile();
self = del;
ei.AddEventHandler(DataProxy, del);
lambda = ex.Expression.Lambda(ei.EventHandlerType, block, parameters);
return true;
}
As I said before, this method should add the Eventhandler passed by Delegate Callback to the Event named string name of the static MAServiceClient DataProxy and remove it after it was called (and the Eventhandler which removes the Callback itsself).
I have a WCF service that accepts an object as a parameter that has a URI and Method Name.
What I am trying to do is have a method that will look # the URI, if it contains the words "localhost" it will use reflection and call a method, of the name that is passed in as a parameter, within the the same class, return a value and continue on.
public class Test
{
public GetStatResponse GetStat(GetStatRequest request)
{
GetStatResponse returnValue = new GetStatResponse();
if(Helpers.Contains(request.ServiceURI,"localhost", StringComparison.OrdinalIgnoreCase))
{
MethodInfo mi = this.GetType().GetMethod(request.ServiceMethod /*, BindingFlags.Public | BindingFlags.IgnoreCase*/);
returnValue = (GetStatResponse)mi.Invoke(this,null);
}
The above is the code segment pertaining to this question. I pull the MethodInfo no problem but I am running into issues on the mi.Invoke. The exception that I receive is "Exception has been thrown by the target of an invocation." With an Inner Exception "Object reference not set to an instance of an object". I have tried changing the code to (GetStatResponse)mi.Invoke(new Test(), null), with no luck. Test being the class.
I'm open to other suggestions as to how to resolve this, I just thought reflection might be the easiest.
The Method that I am calling with my testing is defined as
public GetStatResponse TestMethod()
{
GetStatResponse returnValue = new GetStatResponse();
Stat stat = new Stat();
Stat.Label = "This is my label";
Stat.ToolTip = "This is my tooltip";
Stat.Value = "this is my value";
returnValue.Stat = stat;
return returnValue;
}
Because you are not specifying BindingFlags in your GetMethod() call, you are only going to be returned methods matching the name containing request.ServiceMethod that are PUBLIC.
Check whether the method you are trying to invoke is public, otherwise MethodInfo will return null.
If it is not public, either make the method public or include the BindingFlags.NonPublic flag.
Also, you should always make sure that mi != null before calling mi.Invoke
Before calling the method you might want to make sure that the MethodInfo you are pulling through reflection is not null:
MethodInfo mi = this.GetType().GetMethod(
request.ServiceMethod,
BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase
);
// Make sure that the method exists before trying to call it
if (mi != null)
{
returnValue = (GetStatResponse)mi.Invoke(this, null);
}
After your update it seems that the exception is thrown inside the method you are calling:
GetStatResponse returnValue = new GetStatResponse();
// Don't forget to initialize returnValue.Stat before using it:
returnValue.Stat = new WhateverTheTypeIs();
returnValue.Stat.Label = "This is my label";
How do I define a DynamicMethod for a delegate that has an out-parameter, like this?
public delegate void TestDelegate(out Action a);
Let's say I simply want a method that sets the a argument to null when I call the method.
Note that I know that a probably better way to handle this would be to make the method return the Action delegate, but this is just a simplified part of a larger project, and the method in question already returns a value, I need to handle the out parameter in addition to it, hence the question.
I tried this:
using System;
using System.Text;
using System.Reflection.Emit;
namespace ConsoleApplication8
{
public class Program
{
public delegate void TestDelegate(out Action a);
static void Main(String[] args)
{
var method = new DynamicMethod("TestMethod", typeof(void),
new Type[] { typeof(Action).MakeByRefType() });
var il = method.GetILGenerator();
// a = null;
il.Emit(OpCodes.Ldnull);
il.Emit(OpCodes.Starg, 0);
// return
il.Emit(OpCodes.Ret);
var del = (TestDelegate)method.CreateDelegate(typeof(TestDelegate));
Action a;
del(out a);
}
}
}
However, I get this:
VerificationException was unhandled:
Operation could destabilize the runtime.
on the del(out a); line.
Note that if I comment out the two lines that load a null on the stack and attempts to store it into the argument, the method runs without exceptions.
Edit: Is this the best approach?
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldnull);
il.Emit(OpCodes.Stind_Ref);
An out argument is just a ref argument with the OutAttribute applied to the parameter.
To store to the by-ref argument, you need to use the stind opcode, because the argument itself is a managed pointer to the object's actual location.
ldarg.0
ldnull
stind.ref