I want to create a generic mechanism for handling messages in C#. I have a need for this in my small application, so I don't want to use full blown message bus. My requirements are quite simple:
I want to have a couple of classes for messages i.e. Message1, Message2. They can inherit from one base class, that's not a problem, but if they don't I don't care. Currently they do inherit from Message.
be able to get handler for each and every message class. i.e. if I send Message1, then Message1Handler class should be instantiated. Handlers have to implement IMessageHandler<T> where T is the message class. IMessageHandler is defined as follows:
interface IMessageHandler<T>
{
void Execute(T message);
}
I wrote a simple "Resolver" class:
public static class HandlerRegistry
{
private static readonly Dictionary<string, Type> _handlers = new Dictionary<string, Type>();
public static void Register<T, T2>() where T2: IMessageHandler<T>
{
_handlers.Add(typeof(T).FullName, typeof(T2));
}
public static IMessageHandler<T> Resolve<T>(T parameters)
{
var type = _handlers[parameters.GetType().FullName];
return (IMessageHandler<T>) Activator.CreateInstance(type);
}
}
In this implementation everything is OK, but one part - the cast to IMessageHandler. When I'm trying to use this with a collection of messages this is what happens: the compiler doesn't know at compile time what actual messages are going to be in the collection - it just assumes that they are all subclasses of Message, so it's trying to cast IMessageHandler<ConcreteMessage> to IMessageHandler<Message> and obviously I'm getting an exception with invalid cast. In this case probably contravariance would help, but I'm not able to declare the parameter as out because I have the message in the Execute method parameters.
Does anyone know an elegant solution to this problem? I know I can make it "more runtime" - instead of using generics just declare
void Execute(Message m) and in each and every handler start with trying to cast to the type that I'm expecting, but as someone said somewhere - each and every cast that you write undermines the whole point of using a type system.
Option 1
If you do not care using reflection. You can add a Execute method to your HandlerRegistry instead of returning the handler back to the caller:
public static void Execute<T>(T parameters)
{
var type = _handlers[parameters.GetType().FullName];
var handler = Activator.CreateInstance(type);
type.GetMethod("Execute", new[] { parameters.GetType() })
.Invoke(handler, new object[] { parameters });
}
Option 2
If you do not care that one message handler can only subscribe to one message. We can take advantage of the Explicit Interface Implementation feature of C#:
// NOTE: This interface is not generic
public interface IMessageHandler
{
void Execute(object message);
}
public abstract class MessageHandler<T> : IMessageHandler
{
public abstract void Execute(T message);
// NOTE: Here we explicitly implement the IMessageHandler
void IMessageHandler.Execute(object message)
{
Execute((T)message);
}
}
Now your resolve method can change to:
public static IMessageHandler Resolve<T>(T parameters)
{
var type = _handlers[parameters.GetType().FullName];
return (IMessageHandler)Activator.CreateInstance(type);
}
By the way, personally I would prefer to pass in a Type instead of the message instance.
Then make your handlers inherit from the generic abstract MessageHandler<T> instead of implementing IMessageHandler:
public class HandlerA : MessageHandler<MessageA>
{
public override void Execute(MessageA message)
{
Console.WriteLine("Message A");
}
}
public class HandlerB : MessageHandler<MessageB>
{
public override void Execute(MessageB message)
{
Console.WriteLine("Message B");
}
}
How about this for a message router:
class Tester
{
public void Go()
{
var a = new MessageA();
var b = new MessageB();
var c = new MessageC();
var router = new MessageRouter();
router.RegisterHandler(new HandlerA());
router.RegisterHandler(new HandlerB());
router.Route(a);
router.Route(b);
router.Route(c);
}
}
class MessageRouter
{
Dictionary<Type, dynamic> m_handlers = new Dictionary<Type,dynamic>();
public void RegisterHandler<T>(IMessageHandler<T> handler)
{
m_handlers.Add(typeof(T), handler);
}
public void Route(dynamic message)
{
var messageType = message.GetType();
if (m_handlers.ContainsKey(messageType))
{
m_handlers[messageType].Handle(message);
}
else
{
foreach (var pair in m_handlers)
{
if(pair.Key.IsAssignableFrom(messageType))
{
pair.Value.Handle(message);
}
}
}
}
}
class MessageA
{
public virtual string A { get { return "A"; } }
}
class MessageB
{
public string B { get { return "B"; } }
}
class MessageC :MessageA
{
public override string A { get { return "C"; } }
}
interface IMessageHandler<T>
{
void Handle(T message);
}
class HandlerA : IMessageHandler<MessageA>
{
public void Handle(MessageA message)
{
Console.WriteLine(message.A);
}
}
class HandlerB : IMessageHandler<MessageB>
{
public void Handle(MessageB message)
{
Console.WriteLine(message.B);
}
}
How about taking a slightly different approach: Instead of registering the type of a handler, why not register the actual handler instance which will process the message? This gives you much greater flexibility in instantiation of the handler, and removes any type ambiguities.
The idea is to be able to do this:
// have several handler classes
class FooMessageHandler : IMessageHandler<Foo>
{ }
class BarMessageHandler : IMessageHandler<Bar>
{ }
// have them instantiated - allows you to pass much more context
// than Activator.CreateInstance is able to do
var fooMessageHandler = new FooMessageHandler(various params);
var barMessageHandler = new BarMessageHandler(various params);
// register actual instances
HandlerRegistry.Register<Foo>(fooMessageHandler);
HandlerRegistry.Register<Bar>(barMessageHandler);
// handler registry will simply dispatch the message to
// one of the handlers
HandlerRegistry.Dispatch(someFooMessage);
Not only that, but the approach allows you to register multiple handlers for each message type:
// these will all get called when a Foo message is received
HandlerRegistry.Register<Foo>(fooMessageHandler);
HandlerRegistry.Register<Foo>(someOtherFooHandler);
HandlerRegistry.Register<Foo>(yetAnotherFooHandler);
What if you inherit all you messages from common abstract MessageBase and instead of making message handler interface IMessageHandler<T> generic, put constraint on Execute method itself?
Namely void Execute<T>(T message) where T : MessageBase.
This way you get the desired functionality and your message handler resolver, HandlerRegistry, needs only a minor tweak. Just change return type & constraint from IMessageHandler<T> to IMessageHandler.
Below are slightly modified MessageBase, IMessageHandler and HandlerRegistry.
(Related dotnetfiddle here https://dotnetfiddle.net/e6M1UA)
// Message
public abstract class MessageBase
{
public virtual void Action() // ...for examples sake
{
Console.WriteLine(GetType().Name);
}
}
// Message handler
public interface IMessageHandler
{
void Execute<T>(T message) where T : MessageBase;
}
// Resolver
public static class HandlerRegistry
{
private static readonly Dictionary<string, Type> Handlers =
new Dictionary<string, Type>();
public static void Register<T, T2>() where T2 : IMessageHandler
{
Handlers.Add(typeof(T).FullName, typeof(T2));
}
public static IMessageHandler Resolve<T>(T parameters)
{
var type = Handlers[parameters.GetType().FullName];
return (IMessageHandler)Activator.CreateInstance(type);
}
}
Now, if you test it using e.g. following implementations
public class Message1 : MessageBase
{}
public class Message2 : MessageBase
{
public override void Action()
{
Console.Write(#"Overriding ");
base.Action();
}
}
public class Message1Handler : IMessageHandler
{
public void Execute<T>(T message) where T : MessageBase
{
Console.Write(#"MessageHandler1 > ");
message.Action();
}
}
public class Message2Handler : IMessageHandler
{
public void Execute<T>(T message) where T : MessageBase
{
Console.Write(#"MessageHandler2 > ");
message.Action();
Console.WriteLine(#"...and then some");
}
}
With this block of code
HandlerRegistry.Register<Message1, Message1Handler>();
HandlerRegistry.Register<Message2, Message2Handler>();
var messages = new List<MessageBase>()
{
new Message1(),
new Message2()
};
foreach (var message in messages)
{
var handler = HandlerRegistry.Resolve(message);
handler.Execute(message);
}
You'll end up with console log
MessageHandler1 > Message1
MessageHandler2 > Overriding Message2
...and then some
Related
Scrumbling my head around basics.
I have a couple of (for the example let's say) message classes sharing a common base class. And I have an interface that accepts the base class as argument. So far I thought it would easily be possible to use method overloading to handle specific types of messages in seperated methods.
How could you get this following sample running:
using System;
namespace MethodOverloading
{
// for the example: we are sending messages
// which have a common base class
public class MessageBase
{
public readonly string Value;
public MessageBase() { Value = GetType().Name; }
}
// and there are a couple of concrete instances
public class Message1000 : MessageBase { }
public class Message2000 : MessageBase { }
public class Message3000 : MessageBase { }
public class Message4000 : MessageBase { }
public class Message5000 : MessageBase { }
// and of cource we have an interface receiving all messages but only with one method for the base defined
public interface IHandler
{
void ReceiveMessage(MessageBase msg);
}
// the handlers should do some method overloading so a overloaded method can be implemented for each supported message
// and the base message catches all unsupported messages (e.g. log: ey, missed an overload for this type)
// Handler 1 tries to overload the interface method
public class Handler1 : IHandler
{
public void ReceiveMessage(MessageBase msg) { Console.WriteLine($"Handler1.ReceiveMessage(MessageBase:{msg.Value})"); }
public void ReceiveMessage(Message1000 msg) { Console.WriteLine($"Handler1.ReceiveMessage(Message1000:{msg.Value})"); }
public void ReceiveMessage(Message2000 msg) { Console.WriteLine($"Handler1.ReceiveMessage(Message2000:{msg.Value})"); }
public void ReceiveMessage(Message3000 msg) { Console.WriteLine($"Handler1.ReceiveMessage(Message3000:{msg.Value})"); }
public void ReceiveMessage(Message4000 msg) { Console.WriteLine($"Handler1.ReceiveMessage(Message4000:{msg.Value})"); }
// intentionally no overload for Message5000
}
// Handler 2 provides one interface method and has protected overloads...
public class Handler2 : IHandler
{
public void ReceiveMessage(MessageBase msg)
{
Console.Write($"Handler2.ReceiveMessage(MessageBase:{msg.Value}) > ");
HandleMessage(msg);
}
protected void HandleMessage(MessageBase msg) { Console.WriteLine($"Handler2.HandleMessage(MessageBase:{msg.Value})"); }
protected void HandleMessage(Message1000 msg) { Console.WriteLine($"Handler2.HandleMessage(Message1000:{msg.Value})"); }
protected void HandleMessage(Message2000 msg) { Console.WriteLine($"Handler2.HandleMessage(Message2000:{msg.Value})"); }
protected void HandleMessage(Message3000 msg) { Console.WriteLine($"Handler2.HandleMessage(Message3000:{msg.Value})"); }
protected void HandleMessage(Message4000 msg) { Console.WriteLine($"Handler2.HandleMessage(Message4000:{msg.Value})"); }
// intentionally no overload for Message5000
}
class Program
{
static void Main(string[] args)
{
// so lets give it a try ....
Console.WriteLine("Testing method overloads");
MessageBase msgBase = new MessageBase();
Message1000 msg1000 = new Message1000();
Message2000 msg2000 = new Message2000();
Message3000 msg3000 = new Message3000();
Message4000 msg4000 = new Message4000();
Message5000 msg5000 = new Message5000();
Console.WriteLine("Handler1:");
Handler1 handler1 = new Handler1();
handler1.ReceiveMessage(msgBase);
handler1.ReceiveMessage(msg1000);
handler1.ReceiveMessage(msg2000);
handler1.ReceiveMessage(msg3000);
handler1.ReceiveMessage(msg4000);
handler1.ReceiveMessage(msg5000);
Console.WriteLine("iHandler1:");
IHandler ihandler1 = new Handler1();
ihandler1.ReceiveMessage(msgBase);
ihandler1.ReceiveMessage(msg1000);
ihandler1.ReceiveMessage(msg2000);
ihandler1.ReceiveMessage(msg3000);
ihandler1.ReceiveMessage(msg4000);
ihandler1.ReceiveMessage(msg5000);
Console.WriteLine("Handler2:");
Handler2 handler2 = new Handler2();
handler2.ReceiveMessage(msgBase);
handler2.ReceiveMessage(msg1000);
handler2.ReceiveMessage(msg2000);
handler2.ReceiveMessage(msg3000);
handler2.ReceiveMessage(msg4000);
handler2.ReceiveMessage(msg5000);
Console.WriteLine("iHandler2:");
IHandler ihandler2 = new Handler2();
ihandler2.ReceiveMessage(msgBase);
ihandler2.ReceiveMessage(msg1000);
ihandler2.ReceiveMessage(msg2000);
ihandler2.ReceiveMessage(msg3000);
ihandler2.ReceiveMessage(msg4000);
ihandler2.ReceiveMessage(msg5000);
Console.WriteLine("press any key to exit");
Console.ReadLine();
}
}
}
The output actually is:
Testing method overloads
Handler1:
Handler1.ReceiveMessage(MessageBase:MessageBase)
Handler1.ReceiveMessage(Message1000:Message1000)
Handler1.ReceiveMessage(Message2000:Message2000)
Handler1.ReceiveMessage(Message3000:Message3000)
Handler1.ReceiveMessage(Message4000:Message4000)
Handler1.ReceiveMessage(MessageBase:Message5000)
iHandler1:
Handler1.ReceiveMessage(MessageBase:MessageBase)
Handler1.ReceiveMessage(MessageBase:Message1000)
Handler1.ReceiveMessage(MessageBase:Message2000)
Handler1.ReceiveMessage(MessageBase:Message3000)
Handler1.ReceiveMessage(MessageBase:Message4000)
Handler1.ReceiveMessage(MessageBase:Message5000)
Handler2:
Handler2.ReceiveMessage(MessageBase:MessageBase) > Handler2.HandleMessage(MessageBase:MessageBase)
Handler2.ReceiveMessage(MessageBase:Message1000) > Handler2.HandleMessage(MessageBase:Message1000)
Handler2.ReceiveMessage(MessageBase:Message2000) > Handler2.HandleMessage(MessageBase:Message2000)
Handler2.ReceiveMessage(MessageBase:Message3000) > Handler2.HandleMessage(MessageBase:Message3000)
Handler2.ReceiveMessage(MessageBase:Message4000) > Handler2.HandleMessage(MessageBase:Message4000)
Handler2.ReceiveMessage(MessageBase:Message5000) > Handler2.HandleMessage(MessageBase:Message5000)
iHandler2:
Handler2.ReceiveMessage(MessageBase:MessageBase) > Handler2.HandleMessage(MessageBase:MessageBase)
Handler2.ReceiveMessage(MessageBase:Message1000) > Handler2.HandleMessage(MessageBase:Message1000)
Handler2.ReceiveMessage(MessageBase:Message2000) > Handler2.HandleMessage(MessageBase:Message2000)
Handler2.ReceiveMessage(MessageBase:Message3000) > Handler2.HandleMessage(MessageBase:Message3000)
Handler2.ReceiveMessage(MessageBase:Message4000) > Handler2.HandleMessage(MessageBase:Message4000)
Handler2.ReceiveMessage(MessageBase:Message5000) > Handler2.HandleMessage(MessageBase:Message5000)
press any key to exit
Handler 1 actually works when called directly. Unfortunatly not out of the box when called as interface.
Though I thought at least Handler2 with the protected overloads would do the trick....
What I am actually trying to get rid of is the switch statement with castings in Handler3 (because that extra step could easily be missed and it would be great to do that magic in a base class unaccessible for the developers):
public class Handler3 : IHandler
{
public void ReceiveMessage(MessageBase msg)
{
Console.Write($"Handler3.ReceiveMessage(MessageBase:{msg.Value}) > ");
switch (msg)
{
case Message1000 msg1000: HandleMessage(msg1000); break;
case Message2000 msg2000: HandleMessage(msg2000); break;
case Message3000 msg3000: HandleMessage(msg3000); break;
case Message4000 msg4000: HandleMessage(msg4000); break;
default: Console.WriteLine("dropped because not supported: " + msg.Value); break; // for the msg5000
}
}
//protected void HandleMessage(MessageBase msg) { Console.WriteLine($"Handler3.HandleMessage(MessageBase:{msg.Value})"); }
protected void HandleMessage(Message1000 msg) { Console.WriteLine($"Handler3.HandleMessage(Message1000:{msg.Value})"); }
protected void HandleMessage(Message2000 msg) { Console.WriteLine($"Handler3.HandleMessage(Message2000:{msg.Value})"); }
protected void HandleMessage(Message3000 msg) { Console.WriteLine($"Handler3.HandleMessage(Message3000:{msg.Value})"); }
protected void HandleMessage(Message4000 msg) { Console.WriteLine($"Handler3.HandleMessage(Message4000:{msg.Value})"); }
// intentionally no overload for Message5000
}
Which would actually works as shown by the output:
Handler3:
Handler3.ReceiveMessage(MessageBase:MessageBase) > dropped because not supported: MessageBase
Handler3.ReceiveMessage(MessageBase:Message1000) > Handler3.HandleMessage(Message1000:Message1000)
Handler3.ReceiveMessage(MessageBase:Message2000) > Handler3.HandleMessage(Message2000:Message2000)
Handler3.ReceiveMessage(MessageBase:Message3000) > Handler3.HandleMessage(Message3000:Message3000)
Handler3.ReceiveMessage(MessageBase:Message4000) > Handler3.HandleMessage(Message4000:Message4000)
Handler3.ReceiveMessage(MessageBase:Message5000) > dropped because not supported: Message5000
But it is a benefit that the compiler complains and prevents builds if you miss an method overload using that variant.
Well, yes. Remember that overload resolution is done at compile-time using the compile-time types of your variables, and not at runtime. The runtime types are irrelevant.
IHandler only has the overload void ReceiveMessage(MessageBase msg). So when you call IHandler.ReceiveMessage(msg), whatever subclass msg happens to be, it has to call IHandler.ReceiveMessage(MessageBase msg), because that's the only method which IHandler defines.
It doesn't matter that Handler1 defines other other methods which aren't in IHandler: your Main method is working with an instance of IHandler, and so void ReceiveMessage(MessageBase msg) is the only overload it can see.
In Handler2.ReceiveMessage(MessageBase msg), msg has the compile-time type MessageBase. You can see it in the method signature. So when you call HandleMessage(msg), msg is a MessageBase, so the compiler has to pick the HandleMessage(MessageBase msg) overload.
One possible way to achieve what you're after is to use the visitor pattern. This lets you take a variable with a compile-time type of MessageBase, and find out what its run-time type is by asking it to call a specific method on you. Something like:
public interface IMessageVisitor
{
void Accept(Message1000 msg);
void Accept(Message2000 msg);
}
// for the example: we are sending messages
// which have a common base class
public abstract class MessageBase
{
public readonly string Value;
public MessageBase() { Value = GetType().Name; }
public abstract void Visit(IMessageVisitor visitor);
}
// and there are a couple of concrete instances
public class Message1000 : MessageBase
{
public override void Visit(IMessageVisitor visitor) => visitor.Accept(this);
}
public class Message2000 : MessageBase
{
public override void Visit(IMessageVisitor visitor) => visitor.Accept(this);
}
public interface IHandler
{
void ReceiveMessage(MessageBase msg);
}
public class Handler1 : IHandler, IMessageVisitor
{
public void ReceiveMessage(MessageBase msg) => msg.Visit(this);
public void Accept(Message1000 msg) => Console.WriteLine("Message1000");
public void Accept(Message2000 msg) => Console.WriteLine("Message2000");
}
See it on dotnetfiddle.net.
Methods are resolved based on type of the object, not the type of the parameter. I.e. you will call Handler1.ReceiveMessage or Handler2.ReceiveMessage based on the type of the handler object, not the message object. This is technically known as "single dispatch"
What you want is "multiple dispatch", i.e. you want the method to be resolved based on two different objects.
One way to do this would be to change your interface to an abstract base class and use pattern matching to map the type to the correct method
public abstract class HandlerBase
{
protected abstract void ReceiveMessage(Message1000 msg);
protected abstract void ReceiveMessage(Message2000 msg);
// etc
void ReceiveMessage(MessageBase msg){
switch(msg){
case Message1000 msg1000:
ReceiveMessage(msg1000);
break;
case Message2000 msg2000:
ReceiveMessage(msg2000);
break;
// etc
}
}
}
Another alternative is the visitor pattern:
public abstract class MessageBase
{
public readonly string Value;
public MessageBase() { Value = GetType().Name; }
public abstract void Visit(IVisitor visitor);
}
public class Message1000
{
public override void Visit(IVisitor visitor) => visitor.ReceiveMessage(this);
}
public interface IVisitor{
void ReceiveMessage(Message1000 msg);
void ReceiveMessage(Message2000 msg);
// etc...
}
The visitor pattern will force you to implement all the needed methods, a new message type must have an Accept method, and to implement this you need a new ReceiveMessage overload, and that has to be implemented by all the visitors/handlers. If this is a benefit or not is up to you.
A third alternative is to use "dynamic", but I would not recommend it since it will disable all type checking.
I have a typed factory with this method:
IRepository<T> Get<T>() where T : class
and the following component type selector:
public class RepositoryComponentSelector : DefaultTypedFactoryComponentSelector
{
protected override string GetComponentName(MethodInfo method, object[] arguments)
{
return ComponentNames.Repository;
}
protected override Type GetComponentType(MethodInfo method, object[] arguments)
{
return typeof(Repository<>).MakeGenericType(method.GetGenericArguments()[0]);
}
}
What I would like however, is to have a factory implementation that returns a Repository, but by only having to specify a parameter of type Type, not a compile time type parameter.
Example (not valid code) - I want the T to be the Type provided
IRepository<T> Get(Type type);
I am aware that this does not compile because the method itself has to be generic, but I don't know the parameter beforehand.
What I am trying to achieve is to simplify this pattern:
if (documentType == SomeEnum.x)
{
this.RepositoryFactory.Get<X>().Update(document as X);
}
else if (documentType == SomeEnum.y)
{
this.RepositoryFactory.Get<Y>().Update(document as Y);
}
else if (documentType == SomeEnum.z)
{
this.RepositoryFactory.Get<Z>().Update(document as Z);
}
by resolving the factory based on the enum (or an extension to that enum returning Type).
Is there a way to achieve this with Castle Windsor, or any other approaches I could take?
I believe this is more about polymorphism and general dispatching problem, rather than hooking this into container.
You can use double dispatch approach:
public void Save(DocumentBase document)
{
var dispatcher = new DocumentDispatcher();
document.Accept(dispatcher);
}
public abstract class DocumentBase
{
public abstract void Accept(IDocumentDispatcher dispatcher);
}
public class DocumentA : DocumentBase
{
public override void Accept(IDocumentDispatcher dispatcher)
{
dispatcher.Dispatch(this);
}
}
public class DocumentB : DocumentBase
{
public override void Accept(IDocumentDispatcher dispatcher)
{
dispatcher.Dispatch(this);
}
}
public interface IDocumentDispatcher
{
void Dispatch(DocumentA document);
void Dispatch(DocumentB document);
}
public class DocumentDispatcher : IDocumentDispatcher
{
public void Dispatch(DocumentA document)
{
this.RepositoryFactory.Get<DocumentA>().Update(document);
}
public void Dispatch(DocumentB document)
{
this.RepositoryFactory.Get<DocumentB>().Update(document);
}
}
Alternatively you can use dynamic dispatch:
public void Save(DocumentBase document)
{
var dispatcher = new DocumentDispatcher();
dispatcher.Dispatch((dynamic)document);
}
public class DocumentDispatcher : IDocumentDispatcher
{
public void Dispatch<T>(T document)
{
this.RepositoryFactory.Get<T>().Update(document);
}
}
Or even dictionary dispatch:
public void Save(DocumentBase document)
{
var actions = new Dictionary<Type, Action<DocumentBase>>
{
{ typeof(DocumentA), d => this.RepositoryFactory.Get<DocumentA>().Update((DocumentA)d) },
{ typeof(DocumentB), d => this.RepositoryFactory.Get<DocumentB>().Update((DocumentB)d) },
};
actions[typeof(DocumentBase)](document);
}
I prefer first solution as it is only one type safe solution.
I'm working on a system where a Watcher can be set up to be interested in an Event and invoke an Action if an Event of the correct type is passed in.
Now the Action requires information about the Event when invoked.
In the below code I use delegates as Action properties (not a property in a .NET fashion, just a field/member/whatever...) to which I pass the Event functions when setting up the Watcher.
The Problem of course with the code is that at //Step3, when I do that, the field TheEvent is null. And it will only be known once the Watcher is passed the Event.
How can I tell the Watcher to make it's Action get the required properties from the Event before the Event is assigned?
namespace ConsoleApplication1
{
using System;
internal class Program
{
static void Main(string[] args)
{
//Step1: choose the IEvent: NumericEvent
//Step2: create Watcher<NumbericEvent>
Watcher<NumericEvent> aWatcher = new Watcher<NumericEvent>();
//Step3: Choose and add an action
aWatcher.TheAction = new AlphaAction();
//Step3 bind the ActionProperties
aWatcher.TheAction.AnActionPropertyA = aWatcher.TheEvent.GetProperty1;
aWatcher.TheAction.AnActionPropertyB = aWatcher.TheEvent.GetProperty2;
//Step4 Bind the event
NumericEvent anEvent = new NumericEvent();
aWatcher.Call(anEvent);
}
}
internal class AlphaAction
{
internal delegate string ActionPropertyA();
internal delegate int ActionPropertyB();
internal ActionPropertyA AnActionPropertyA;
internal ActionPropertyB AnActionPropertyB;
internal string ActionPropertyC;
public void Run()
{
Console.Write(AnActionPropertyA.Invoke());
Console.Write(AnActionPropertyB.Invoke());
}
}
internal interface IEvent
{
}
internal class NumericEvent:IEvent
{
internal string EventProperty1 = "Property1";
internal int EventProperty2 = 2;
internal string GetProperty1()
{
return EventProperty1;
}
internal int GetProperty2()
{
return EventProperty2;
}
}
internal class Watcher<T> where T:IEvent
{
internal NumericEvent TheEvent;
internal AlphaAction TheAction;
internal void Call(IEvent anEvent)
{
TheEvent = (NumericEvent)anEvent;
TheAction.Run();
}
}
}
Maybe a completely different approach needs to be taken but I hope this gets the problem and the desired outcome across.
UPDATE
I've made some progerss with using Delegate.CreateDelegate (https://msdn.microsoft.com/en-us/library/s3860fy3.aspx) but it's still not quite right as it's treating it as static if null when assigned:
namespace ConsoleApplication1
{
using System;
using System.Reflection;
internal class Program
{
static void Main(string[] args)
{
//Step1: choose the IEvent: NumericEvent
//Step2: create Watcher<NumbericEvent>
Watcher<NumericEvent> aWatcher = new Watcher<NumericEvent>();
//Step3: Choose and add an action
aWatcher.TheAction = new AlphaAction();
//Step3 bind the ActionProperties
MethodInfo method1 = typeof(NumericEvent).GetMethod("GetProperty1");
aWatcher.TheAction.AnActionPropertyA = (AlphaAction.ActionPropertyA)Delegate.CreateDelegate(typeof(AlphaAction.ActionPropertyA), aWatcher.TheEvent, method1);
MethodInfo method2 = typeof(NumericEvent).GetMethod("GetProperty2");
aWatcher.TheAction.AnActionPropertyB = (AlphaAction.ActionPropertyB)Delegate.CreateDelegate(typeof(AlphaAction.ActionPropertyB), aWatcher.TheEvent, method2);
//Step4 an event is created and passed to the Watcher
NumericEvent anEvent = new NumericEvent("bla",3);
if (aWatcher.GType() == anEvent.GetType())
aWatcher.Call(anEvent);
}
}
internal abstract class BaseAction
{
public abstract void Run();
}
internal class AlphaAction: BaseAction
{
internal delegate string ActionPropertyA();
internal delegate int ActionPropertyB();
internal ActionPropertyA AnActionPropertyA;
internal ActionPropertyB AnActionPropertyB;
internal string ActionPropertyC;
public override void Run()
{
Console.Write(AnActionPropertyA.Invoke());
Console.Write(AnActionPropertyB.Invoke());
}
}
internal interface IEvent
{
}
internal class NumericEvent : IEvent
{
private readonly string _eventProperty1;
private readonly int _eventProperty2;
public NumericEvent(string p1, int p2)
{
_eventProperty1 = p1;
_eventProperty2 = p2;
}
public string GetProperty1()
{
return _eventProperty1;
}
public int GetProperty2()
{
return _eventProperty2;
}
}
internal class Watcher<T> where T:IEvent
{
internal T TheEvent;
internal AlphaAction TheAction;
internal Type GType()
{
return typeof(T);
}
internal void Call(IEvent anEvent)
{
TheEvent = (T)anEvent;
TheAction.Run();
}
}
}
The problem with your code is the aWatcher.TheEvent in the aWatcher.TheAction.AnActionPropertyA = aWatcher.TheEvent.GetProperty1; line (and in the updated code aWatcher.TheAction.AnActionPropertyA = (AlphaAction.ActionPropertyA)Delegate.CreateDelegate(typeof(AlphaAction.ActionPropertyA), aWatcher.TheEvent, method1);).
Because aWatcher.TheEvent is null at the time the delegate is created the delegate always uses null. It doesn't care that you later assign the event in the line TheEvent = (NumericEvent)anEvent;.
To get this to work you need to let the delegate know that there is a class coming in the future. Here's how I would do it, but I suspect this will break something in your logic of how you want it to work.
void Main()
{
Watcher<NumericEvent> aWatcher = new Watcher<NumericEvent>();
aWatcher.TheAction = new AlphaAction<NumericEvent>();
aWatcher.TheAction.AnActionPropertyA = ne => ne.GetProperty1();
aWatcher.TheAction.AnActionPropertyB = ne => ne.GetProperty2();
NumericEvent anEvent = new NumericEvent("bla", 3);
if (aWatcher.GType() == anEvent.GetType())
aWatcher.Call(anEvent);
}
internal abstract class BaseAction<T> where T : IEvent
{
public abstract void Run(T theEvent);
}
internal class AlphaAction<T> : BaseAction<T> where T : IEvent
{
internal delegate string ActionPropertyA(T theEvent);
internal delegate int ActionPropertyB(T theEvent);
internal ActionPropertyA AnActionPropertyA;
internal ActionPropertyB AnActionPropertyB;
public override void Run(T theEvent)
{
Console.Write(AnActionPropertyA(theEvent));
Console.Write(AnActionPropertyB(theEvent));
}
}
internal interface IEvent
{
}
internal class NumericEvent : IEvent
{
private readonly string _eventProperty1;
private readonly int _eventProperty2;
public NumericEvent(string p1, int p2)
{
_eventProperty1 = p1;
_eventProperty2 = p2;
}
public string GetProperty1()
{
return _eventProperty1;
}
public int GetProperty2()
{
return _eventProperty2;
}
}
internal class Watcher<T> where T : IEvent
{
internal AlphaAction<T> TheAction;
internal Type GType()
{
return typeof(T);
}
internal void Call(T theEvent)
{
TheAction.Run(theEvent);
}
}
If I understand your need well then you can make use of Galasoft's MVVM Light Toolkit.
The point is the following:
Define a message type, e.g. SomeMessage
Register for this type of message where you want to be notified.
An "event" can be raised by sending an instance of SomeMessage.
All the action will be executed that are registered for this message.
Let's take an example:
// First you create the message with the needed properties.
public SomeMessage
{
public string Content { get; set; }
}
// Then at some places you register for listening to this type of message
Messenger.Default.Register<SomeMessage>(
this,
message => YourMethodThatProcessesTheMessage(message)
);
// Your method knows the exact type of the message
// So you can access all the properties of the message
private void YourMethodThatProcessesTheMessage(SomeMessage message)
{
Console.WriteLine(message.Content);
}
// At another place you can simply send a message to all the listeners
var message = new SomeMessage() { Content = "something" };
Messenger.Default.Send<SomeMessage>(message);
If I understand you correctly you want to do the following: Have a Watcher class which looks for a specific event and when it gets passed to the class an action should be fired and the event should be passed in as argument.
I do not fully understand why you need the hole thing and why you set up the things the way you did but here is a simple implementation that might help:
internal interface IEvent { }
internal class Watcher<T> where T : IEvent
{
internal Action<T> Action;
public void On(IEvent evnt)
{
if (evnt is T) Action?.Invoke((T) evnt);
}
}
You can create new events by implementing IEvent and you can register actions which should be fired when an action by the specified type is registered by the watcher by setting the Action field. e.g.
var watcher = new Watcher<NumberEvent>();
watcher.Action += e => Console.WriteLine($"Got a number: {e.Number}");
watcher.On(new StringEvent { Text = "hello"});
watcher.On(new NumberEvent { Number = 1337});
when these are defined
internal class NumberEvent : IEvent
{
internal int Number;
}
internal class StringEvent : IEvent
{
internal string Text;
}
If I did not understand your problem correctly (and there is a great chance I did not) please explain what your program is supposed to do.
Here are some thoughts/questions on your implementation:
You are creating a generic watcher class (Watcher<T>) but T is not used inside of the watcher. You might want to replace NumericEvent by T and do some checking if the specified IEvent is of the type T (or in your case NumericEvent). Your coding makes IEvent pretty much obsolete.
C# has properties string EventProperty { get; }. You do not have to make a GetProperty1() method (also your field is internal so why use the method?)
Just supply the event to the action and do not try to hotwire the event to the action.
Here is my code:
static class MessageHandler<T> where T : Message
{
public delegate void MessageDelegate(T m);
private static MessageDelegate messageHandlers;
public static void Publish(T message)
{
messageHandlers(message);
}
public static void Subscribe(MessageDelegate messageHandler)
{
messageHandlers += messageHandler;
}
}
Message is just an empty class that other classes can inherit from. Most Message derivations are simple objects with relevant properties (this is for a game so there might be a PlayerDamagedMessage with the damage and assailant as the properties.)
Basically, in the Player class when they are attacked they would publish a PlayerDamagedMessage and then other classes that want to know about that can subscribe and then receive the relevant details when it occurs.
The reason why this works with more than one message is because the way generic classes work in C#. By this I mean that there will be a copy of the delegate for each different generic type used under the covers.
I actually figured this out by accident while playing around and am excited because it really simplified my code and looks almost like a design pattern at this point.
I'm posting here to ask about the potential downsides for using this kind of approach. Is there a limit to the amount of generic delegates under the covers? How well would something like this scale?
Also, is there any way to have some sort of generic type-inference so that the statements don't have to be this long?
MessageHandler<MessagePlayerDamaged>.Publish(new MessagePlayerDamaged(this, this));
I've actually used a very similar pattern with much success. One further step I took was encapsulating the actual message handlers within a MessageHandlerRegistry to allow for cleaner syntax. Here is your example modified:
Message.cs
public class Message
{
}
MessageHandler.cs
public class MessageHandler<T> where T : Message
{
private Action<T> messageHandlers;
public void Publish(T message)
{
messageHandlers(message);
}
public void Subscribe(Action<T> messageHandler)
{
messageHandlers = (Action<T>) Delegate.Combine(messageHandlers, messageHandler);
}
}
MessageHandlerRegistry.cs
public static class MessageHandlerRegistry
{
private static readonly IDictionary<Type, object> _handlers = new Dictionary<Type, object>();
public static void Publish<T>(T m) where T : Message
{
if (_handlers.ContainsKey(typeof (T)))
{
((MessageHandler<T>) _handlers[typeof (T)]).Publish(m);
}
}
public static void Subscribe<T>(Action<T> messageHandler) where T : Message
{
if (!_handlers.ContainsKey(typeof (T)))
{
_handlers[typeof (T)] = new MessageHandler<T>();
}
((MessageHandler<T>) _handlers[typeof (T)]).Subscribe(messageHandler);
}
}
Program.cs
class Program
{
static void Main(string[] args)
{
MessageHandlerRegistry.Subscribe((Message m) => Console.WriteLine("Message received."));
MessageHandlerRegistry.Publish(new Message());
}
}
The only downside I have seen to this is being overly-loosly coupled, and in some situations where it would make more sense to use a traditional event based approach, sometimes it is easier to just publish a message.
The main differences to C# events:
Your messages are identified by their Arguments-Class which makes it impossible to have two different events serving alike purposes (think of MouseUp, MouseDown, MouseMoved, etc.)
Your messages are coupled to a static context, not to objects, which makes it hard to register for events from say player1 and not player2
And your messages can be invoked from anywhere at all, whereas event invocations are always private to the class/object owning that event
There is a solution I use in my projects.
public class MessageDispatcher {
private readonly Dictionary<Type, MulticastDelegate> registeredHandlers = new Dictionary<Type, MulticastDelegate>();
private delegate void MessageActionDelegate<in T>(T message);
public void Register<T>(Action<T> action) {
Type messageType = typeof (T);
if (registeredHandlers.ContainsKey(messageType)) {
var messageDelegate = (MessageActionDelegate<T>) registeredHandlers[messageType];
registeredHandlers[messageType] = messageDelegate + new MessageActionDelegate<T>(action);
}
else {
registeredHandlers.Add(messageType, new MessageActionDelegate<T>(action));
}
}
public void Deregister<T>() {
Type messageType = typeof (T);
if (registeredHandlers.ContainsKey(messageType)) {
registeredHandlers.Remove(messageType);
}
}
public void DeregisterAll() {
registeredHandlers.Clear();
}
public void Send<T>(T message) {
Type messageType = typeof (T);
if (!registeredHandlers.ContainsKey(messageType)) return;
((MessageActionDelegate<T>) registeredHandlers[messageType])(message);
}
}
And test example:
private static void Main(string[] args) {
var messenger = new MessageDispatcher();
messenger.Register<Message>(m => Console.WriteLine(m.Text));
messenger.Send(new Message() { Text = "Good morning, sir."});
messenger.Register<Message>(m => Console.WriteLine(m.Text + " It's nice weather today."));
messenger.Register<Notification>(n => Console.WriteLine(n.Text));
messenger.Send(new Message() { Text = "How do you feel? "});
messenger.Send(new Notification() { Text = "Cup of tea, sir?" });
messenger.Deregister<Message>();
messenger.Send(new Message() { Text = "Good bye" });
Console.ReadLine();
}
public class Message {
public string Text { get; set; }
}
public class Notification {
public string Text { get; set; }
}
You can make MessageDispatcher a singleton.
And if your application is multi-threaded then you need to think about thread-safety.
I found a way to do it using generics, I added a private Registry class which stores the static delegate:
class Message
{
}
class MessageHandler
{
public static void Publish<T>(T message) where T : Message
{
Registry<T>.action(message);
}
public static void Subscribe<T>(Action<T> h) where T : Message
{
Registry<T>.action += h;
}
private class Registry<T> where T : Message
{
public static Action<T> action;
}
}
This way you don't have to add the type arguments:
class IntMessage : Message
{
public int Value = 100;
}
class StringMessage : Message
{
public string Value = "a string";
}
static void Main(string[] args)
{
MessageHandler.Subscribe((StringMessage m) => Console.WriteLine("String : " + m.Value));
MessageHandler.Subscribe((StringMessage m) => Console.WriteLine("2nd String : " + m.Value));
MessageHandler.Subscribe((IntMessage m) => Console.WriteLine("Int : " + m.Value));
MessageHandler.Subscribe((IntMessage m) => Console.WriteLine("2nd Int : " + m.Value));
MessageHandler.Publish(new IntMessage());
MessageHandler.Publish(new StringMessage());
}
How to avoid a pair of repetitive lines before and after invocations in sample below ?
Details: This is compileable mock of what is real larger code. Generally it is a layer of proxy classes containing service clients with variety of APIs. The repetitive part is pre- and post- invocation for every method of every client. Unfortunately there is no single signature for all possible methods, the pre- and post- parts need a pointer to client's channel and context.
Is it possible to apply something advanced like AOP, Generics, Delegates, Attributes etc. ? Thank you
using System;
namespace ConsoleApplication
{
class ClassServiceClient: IDisposable
{
public Object channel()
{
return "something";
}
public Object context()
{
return "something other";
}
}
class ClassA : ClassServiceClient
{
public Object methodA()
{
return "something other";
}
}
class ClassB : ClassServiceClient
{
public void methodB(string param)
{
return;
}
}
class ClassAProxy
{
public Object methodA()
{
using (ClassA client = new ClassA())
{
Program.preparation(client.channel()); //<---- repetitive part
Object result = client.methodA();
Program.postinvocation(client.context());//<---- repetitive part
return result;
}
}
}
class ClassBProxy
{
public void methodB(string param)
{
using (ClassB client = new ClassB())
{
Program.preparation(client.channel()); //<---- repetitive part
client.methodB(param);
Program.postinvocation(client.context());//<---- repetitive part
return;
}
}
}
class Program
{
public static void preparation(Object channel)
{
// Do something with channel
}
public static void postinvocation(Object context)
{
// Do something with context
}
static void Main(string[] args)
{
}
}
}
If you can use a common base class, you can easily use a public sealed method that does the invocation and a protected abstract method that does the logic, e.g.
class ProxyBase{
public void Method(params object[] args){
PreConditions();
Invoke(args);
PostConditions();
}
protected abstract void Invoke(object[] args);
}
class ClassAProxy{
protected override void Invoke(object[] args){
client.Method(args[0]);
}
}
You can achieve similar results functionally by declaring a InvocationHandler in your Program class that takes an action:
class Program{
public static void Invoke(object[] args, Action action){
PreConditions();
action();
PostConditions();
}
}
class ClassAProxy{
public void MethodA(int i){
Program.Invoke(() => client.Something(i));
}
}