I'm working on the some kind of EventSourcing architecture and have 2 main concepts in my app - events and handlers.
Events example:
class NewRecordCreated: EventMessage {...}
And there some handlers looks like:
class WriteDBHandler: IEventHandler<NewRecordCreated>, IEventHandler<RecordUpdated> {
public void Handle(NewRecordCreated eventMessage) {...}
public void Handle(RecordUpdated eventMessage) {...}
}
And also I have custom implementation of queue protocol which dispatch events to proper handlers. So basically on app startup I parse assembly and create mapping between event and handlers based on types.
So when I actually dispatching events to handlers I based on event type getting chain of handler's types - something like var handlerChain = [typeof(WriteDbHandler), typeof(LogHandler), typeof(ReadModelUpdateHandler)] and for each of those handlers I need to invoke it's instance, then cast it to proper interface (IEventHandler<>) and than invoke Handle method.
But I can't cast to generic interface, since it's not possible. I think about options of implementing non generic version of interface, but it's seems quite unpleasant for me to add extra method implementation each time, especially if there no any real reasons for it.
I think about dynamic invocation or reflection, but both of this variants seems have performance issues. Maybe you could advice me some suitable alternatives?
Using reflection
Rather than trying to cast to IEventHandler<>, you can instead use reflection to get a reference to the method you need to invoke. The code below is a good example. It simplifies the "queue protocol" for sake of brevity, but it should sufficiently illustrate the reflection that you need to do.
class MainClass
{
public static void Main(string [] args)
{
var a = Assembly.GetExecutingAssembly();
Dictionary<Type, List<Type>> handlerTypesByMessageType = new Dictionary<Type, List<Type>>();
// find all types in the assembly that implement IEventHandler<T>
// for some value(s) of T
foreach (var t in a.GetTypes())
{
foreach (var iface in t.GetInterfaces())
{
if (iface.GetGenericTypeDefinition() == typeof(IEventHandler<>))
{
var messageType = iface.GetGenericArguments()[0];
if (!handlerTypesByMessageType.ContainsKey(messageType))
handlerTypesByMessageType[messageType] = new List<Type>();
handlerTypesByMessageType[messageType].Add(t);
}
}
}
// get list of events
var messages = new List<EventMessage> {
new NewRecordCreated("one"),
new RecordUpdated("two"),
new RecordUpdated("three"),
new NewRecordCreated("four"),
new RecordUpdated("five"),
};
// process all events
foreach (var msg in messages)
{
var messageType = msg.GetType();
if (!handlerTypesByMessageType.ContainsKey(messageType))
{
throw new NotImplementedException("No handlers for that type");
}
if (handlerTypesByMessageType[messageType].Count < 1)
{
throw new NotImplementedException("No handlers for that type");
}
// look up the handlers for the message type
foreach (var handlerType in handlerTypesByMessageType[messageType])
{
var handler = Activator.CreateInstance(handlerType);
// look up desired method by name and parameter type
var handlerMethod = handlerType.GetMethod("Handle", new Type[] { messageType });
handlerMethod.Invoke(handler, new object[]{msg});
}
}
}
}
I compiled this and ran it on my machine and got what I believe are the correct results.
Using run-time code generation
If reflection is not fast enough for your purposes, you can compile code on-the-fly for each input message type and execute that.
The System.Reflection.Emit namespace has facilities for doing just that.
You can define a dynamic method (not to be confused with the dynamic keyword, which is something else), and emit a sequence if IL opcodes that will run each handler in the list in sequence.
public static Dictionary<Type, Action<EventMessage>> GenerateHandlerDelegatesFromTypeLists(Dictionary<Type, List<Type>> handlerTypesByMessageType)
{
var handlersByMessageType = new Dictionary<Type, Action<EventMessage>>();
foreach (var messageType in handlerTypesByMessageType.Keys)
{
var handlerTypeList = handlerTypesByMessageType[messageType];
if (handlerTypeList.Count < 1)
throw new NotImplementedException("No handlers for that type");
var method =
new DynamicMethod(
"handler_" + messageType.Name,
null,
new [] { typeof(EventMessage) });
var gen = method.GetILGenerator();
foreach (var handlerType in handlerTypeList)
{
var handlerCtor = handlerType.GetConstructor(new Type[0]);
var handlerMethod =
handlerType.GetMethod("Handle", new Type[] { messageType });
// create an object of the handler type
gen.Emit(OpCodes.Newobj, handlerCtor);
// load the EventMessage passed as an argument
gen.Emit(OpCodes.Ldarg_0);
// call the handler object's Handle method
gen.Emit(OpCodes.Callvirt, handlerMethod);
}
gen.Emit(OpCodes.Ret);
var del = (Action<EventMessage>)method.CreateDelegate(
typeof(Action<EventMessage>));
handlersByMessageType[messageType] = del;
}
}
Then, instead of invoking the handlers with handlerMethod.Invoke(handler, new object[]{msg}), you just call the delegate like any other, with handlersByMessageType[messageType](msg).
Full code listing here.
The actual code generation is done in the GenerateHandlerDelegatesFromTypeLists method.
It instantiates a new DynamicMethod, gets its associated ILGenerator, and then emits opcodes for each handler in turn.
For each handler type, it will instantiate a new object of that handler type, load the event message onto the stack, and then execute the Handle method for that message type on the handler object.
This is of course assuming that the handler types all have zero-parameter constructors.
If you need to pass arguments to the constructors, though, you'll have to modify it considerably.
There are other ways to speed this up even more.
If you relax the requirement to create a new handler object with every message, then you could just create the objects while generating the code, and load them.
In that case, replace gen.Emit(OpCodes.Newobj, handlerCtor) with gen.Emit(OpCodes.Ldobj, handlerObjectsByType[handlerType]).
That gives you two benefits:
1. you're avoiding an allocation on every message
2. you can instantiate the objects any way you want when you populate the handlerObjectsByType dictionary. You can even use constructors with parameters or factory methods.
Related
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.
I'm writing a framework, one function of which involves remotely handling events (details of which I believe aren't relevant right now). What is needed though is the ability to hook an event handler to any event, given the target object reference and event name.
The method that handles the event will marshal/otherwise proxy the parameters to some handler code, then cast the return type to the event handler's return type. Effectively, it wraps the handler.
I believe that due to the fact that the event handler may be required to have any number of parameters of any type, the only way to handle a request to hook an event on-demand is to use reflection/emit (code generation) to build a custom proxy method. I'm posting this question to check that assumption and see if anyone has any other/neater ideas.
Currently, I create a DynamicMethod, then do this kind of thing. It works - almost - but the wrapper method that this dynamic proxy method calls must be static (the declaration is pretty much public static object GenericHandler(object[] parameters)); I don't want it to be. So my current task is to dynamically create a whole type, with this method, but also a field to store the instance of the object to call the wrapper on. But, that's beside the point (I think) - I want to check that my assumption about having to create dynamic code at all is correct or not. But, for ref:
// obj = target object, eventName = event name
var evtInfo = obj.GetType().GetEvent(eventName);
var handlerType = evtInfo.EventHandlerType;
var eventInvokeMethod = handlerType.GetMethod("Invoke");
var paramTypes = eventInvokeMethod.GetParameters().Select(p => p.ParameterType).ToArray();
var returnType = eventInvokeMethod.ReturnType;
var handlerMethod = new DynamicMethod(
"evtHandler_" + eventName,
MethodAttributes.Static | MethodAttributes.Public,
CallingConventions.Standard,
returnType,
paramTypes,
typeof(my container class).Module,
false);
var il = handlerMethod.GetILGenerator();
// locals: [0] = parameter array
il.DeclareLocal(typeof(object[]));
// create an appropriately-sized array objects, for the parameters
il.Emit(OpCodes.Ldc_I4, (int)paramTypes.Count());
il.Emit(OpCodes.Newarr, typeof(object));
il.Emit(OpCodes.Stloc_0);
for (int i = 0; i < paramTypes.Length; i++)
{
// for the array: load the parameter into the same index of the array
il.Emit(OpCodes.Ldloc_0);
il.Emit(OpCodes.Ldc_I4, i);
il.Emit(OpCodes.Ldarg, i);
if (!paramTypes[i].IsClass)
{
// box the value first..
il.Emit(OpCodes.Box, paramTypes[i]);
}
il.Emit(OpCodes.Stelem_Ref);
}
// call our generic handler with the array of parameters, then convert the return
// value to the target type via unboxing or a cast
il.Emit(OpCodes.Ldloc_0);
il.Emit(OpCodes.Call, wrapper.GetMethodInfo());
if (!returnType.IsClass)
{
il.Emit(OpCodes.Unbox_Any, returnType);
}
else
{
il.Emit(OpCodes.Castclass, returnType);
}
il.Emit(OpCodes.Ret);
If there are no responses and I get the above theory with wrapper type working, I'll post updated code.. but would love to hear about alternatives to this method if they are out there.
It was necessary to implement (and improve upon) the above code. With a dynamically-generated assembly, type and method, I can proxy any events fired to a general object HandleEvent(object[] parameters) method.
What I effectively want to do is something like this (I realise this is not valid code):
// Attach the event.
try
{
EventInfo e = mappings[name];
(e.EventHandlerType) handler = (sender, raw) =>
{
AutoWrapEventArgs args = raw as AutoWrapEventArgs;
func.Call(this, args.GetParameters());
};
e.AddEventHandler(this, handler);
}
...
Now I know that the e.EventHandlerType will always derive from EventHandler<AutoWrapEventArgs>. However, I can't just do:
EventHandler<AutoWrapEventArgs> handler = (sender, raw) =>
{
AutoWrapEventArgs args = raw as AutoWrapEventArgs;
func.Call(this, args.GetParameters());
};
e.AddEventHandler(this, handler);
As .NET complains that there is no conversion applicable from EventHandler<AutoWrapEventArgs> to EventHandler<DataEventArgs> when AddEventHandler is called. This is the exact message:
Object of type 'System.EventHandler`1[IronJS.AutoWrapObject+AutoWrapEventArgs]'
cannot be converted to type
'System.EventHandler`1[Node.net.Modules.Streams.NodeStream+DataEventArgs]'.
I have also tried using Invoke to dynamically use the constructor of e.EventHandlerType, but there's no way to pass the delegate definition to Invoke()'s parameter list (because there is no conversion from delegate to object).
Is there a way I can use reflection to get around this problem?
Bingo! The trick is to get a reference to the constructor for the delegate type and then invoke it using the following parameters:
The target object of the delegate (backend.Target)
The delegate's pointer (backend.Method.MethodHandle.GetFunctionPointer())
The actual code that does this looks like (t in this case is the generic argument provided to EventHandler<> during inheritance):
Type t = e.EventHandler.GetGenericArguments()[0];
Delegate handler = (Delegate)
typeof(EventHandler<>)
.MakeGenericType(t)
.GetConstructors()[0]
.Invoke(new object[]
{
backend.Target,
backend.Method.MethodHandle.GetFunctionPointer()
});
You can then use the delegate for the event adding like so:
e.AddEventHandler(this, handler);
You can use Delegate.CreateDelegate to accomplish your goal like this:
public void RegisterHandler(string name)
{
EventInfo e = mappings[name];
EventHandler<AutoWrapEventArgs> handler = (s, raw) =>
{
func.Call(this, raw.GetParameters());
};
e.AddEventHandler(this, Delegate.CreateDelegate(e.EventHandlerType, null, handler.Method));
}
I am looping thru the ObjectStateEntry of EF so I can access enrty.Entity, I am doing some static validation on the poco classes and i want to also do business rule validation so i created a library to do that, now i have this line of code that expect a type excample Customer..
MyEntityValidator<needtypehere> ev = new MyEntityValidator<needtyehere>(new EntityValidator());
so I am having problem passing type where i mentiened 'needtypehere'. I tried entry.Entity.GetType() but not working . Again this is the signiture of the method
GetErrors(this ObjectStateEntry entry)
To invoke generics from a Type instance, you would have to use:
Type closedType = typeof(MyEntityValidator<>)
.MakeGenericType(entry.Entity.GetType());
object obj = Activator.CreateInstance(closedType);
which is... awkward - as you then need to do lots of additional work with reflection. Alternatively, you can call into a generic method that does the code:
public static void InvokeGeneric<T>(...) {
MyEntityValidator<T> ev = new MyEntityValidator<T>(
new EntityValidator());
... etc; lots more code that uses ev
}
...
typeof(ContainingType).GetMethod("InvokeGeneric").MakeGenericMethod(
entry.Entity.GetType()).Invoke(null, args);
You can use MakeGenericType.
I have several message queues that have specific messages on them.
I've created classes for these messages using xsd.exe.
I can receive a message syncronously and deseriazlise it with this method:
public oneOfMyTypes DeserializeMessage(XDocument message)
{
var serializer = new XmlSerializer(typeof(oneOfMyTypes));
var entity = (oneOfMyTypes)serializer.Deserialize(message.CreateReader());
return entity;
}
I then persist the entity via Fluent NHibernate.
So I've got about five message queues that all have their own type of message.
I would like to keep this little processor app maintainable, so that adding more message queues and message types doesn't become a pain.
So I have a list of queue names in my app.config that I use to create the message queues on start up and then I want to wire up a single method to the .ReceiveCompleted event of all queues:
void queue_ReceiveCompleted(object sender, ReceiveCompletedEventArgs e)
{
var queue = (MessageQueue)sender;
var message = queue.EndReceive(e.AsyncResult);
var body = message.Body.ToString();
var xml = XDocument.Parse(body);
var queueName = queue.QueueName;
Type entityType = GetTypeFromQueueName(queueName);
entityType entity = DeserializeMessage<entityType>(xml);
var repository = new LogRepository();
repository.AddEntity<entityType>(entity);
}
private T DeserializeMessage<T>(XDocument message)
{
var serializer = new XmlSerializer(typeof(T));
var entity = (T)serializer.Deserialize(message.CreateReader());
return entity;
}
public Type GetTypeFromQueueName(string queueName)
{
switch (queueName)
{
case "some-message-queue-name":
return typeof (oneOfMyTypes);
}
}
But when I try to pass entityType to the generic methods I get "Type or namespace name expected".
I'm probably doing something really silly, but I can't figure out how this should work.
I've tried using the dynamic keyword and also .MakeGenericType but no luck.
I've also looked at:
Dynamic Generic declaration of type T
Function returning a generic type whose value is known only at runtime
Determining a Generic Type at Runtime in Non-Generic Class
How to pass variable of type "Type" to generic parameter
But I'm still not getting it ... help?
Unfortunately, generics are not meant to function dynamically like this. Generic parameters must be defined at design time. It's been a while since I've used NHibernate, but isn't there a way to insert entities with a syntax like:
repository.AddEntity(entity, typeof(myEntityType));
EDIT:
or
Session.SaveOrUpdate(object);
This link should help you
http://todotnet.com/post/2006/11/13/Instantiating-Generic-Types-at-runtime.aspx
You should be able to go from the link i posted to call the methode through reflection.
See the following link:
http://www.victorchen.info/call-static-method-with-a-string-name/
So basically when you've created your generic Type, you then grab the MethodInfo of your static method and then call the Invoke method on the MethodInfo object.
(i haven't actually tried this but in theory i believe it should work)