using System;
using System.Collections;
using System.Reflection;
namespace MyApp
{
/// <summary>
/// A wrapper for parameters sent to the event handlers.
/// </summary>
public class EventArgs : System.EventArgs
{
public object[] args;
/// <summary>
/// Constructor.
/// </summary>
/// <param name="args">The event's parameters or null.</param>
public EventArgs(object[] args) {this.args=args;}
}
/// <summary>
/// Abstract base class for all event handlers.
/// </summary>
public abstract class EventSink
{
/// <summary>
/// Invokes the event.
/// </summary>
/// <param name="sender">The originator of the event.</param>
/// <param name="args">Parameters to pass to the event handler.</param>
/// <returns>An IAsyncResult object for asynchronous events, or null if the event is invoked synchronously.</returns>
public abstract IAsyncResult Invoke(object sender, object[] args);
}
/// <summary>
/// Abstract class that manages events declared by specifying the instance and method that will handle the event.
/// </summary>
public abstract class EventHandlerSink : EventSink
{
protected EventHandler eh;
/// <summary>
/// Constructor.
/// </summary>
/// <param name="eh">The method that will handle the event.</param>
public EventHandlerSink(System.EventHandler eh)
{
this.eh=eh;
}
}
/// <summary>
/// Abstract class that manages events bound at runtime and declared through reflection (the assembly, namespace, instance, and method names)
/// of the method that will handle the event.
/// </summary>
public abstract class ReflectionSink : EventSink
{
protected MethodInfo mi;
protected object instance;
protected BindingFlags bindingFlags;
/// <summary>
/// Constructor using information compiled by the EventManager object. This method is used for the
/// runtime binding of static methods.
/// </summary>
/// <param name="mi">A MethodInfo object.</param>
public ReflectionSink(MethodInfo mi)
{
this.mi=mi;
instance=null;
bindingFlags=BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.InvokeMethod | BindingFlags.Static;
}
/// <summary>
/// Constructor using the method's object instance and information compiled by the EventManager object. This
/// method is used for the runtime binding of non-static methods.
/// </summary>
/// <param name="instance">The instance associated with the reflection method.</param>
/// <param name="mi">A MethodInfo object.</param>
public ReflectionSink(object instance, MethodInfo mi)
{
this.mi=mi;
this.instance=instance;
bindingFlags=BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.InvokeMethod | BindingFlags.Instance;
}
}
/// <summary>
/// SyncEvent handles the synchronous invocation of events bound using an event delegate.
/// </summary>
public class SyncEventHandlerSink : EventHandlerSink
{
/// <summary>
/// Constructor.
/// </summary>
/// <param name="eh">The method that will handle the event.</param>
public SyncEventHandlerSink(System.EventHandler eh) : base(eh) {}
/// <summary>
/// Invoke the synchronous event handler as declared by the delegate.
/// </summary>
/// <param name="sender">The originator of the event.</param>
/// <param name="args">Any parameters passed to the event.</param>
/// <returns>This method always returns a null because the event is invoked synchronously.</returns>
public override IAsyncResult Invoke(object sender, object[] args)
{
try
{
eh(sender, new EventArgs(args));
}
catch (Exception e)
{
Dbg.Warn(false, new DbgKey("EvMgrInvokeError"), e.ToString());
}
return null;
}
}
/// <summary>
/// ReflectionSyncEvent handles the synchronous invocation of events bound by reflection.
/// </summary>
public class SyncReflectionSink : ReflectionSink
{
/// <summary>
/// Constructor.
/// </summary>
/// <param name="mi">A MethodInfo object.</param>
public SyncReflectionSink(MethodInfo mi) : base(mi) {}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="instance">The instance associated with the reflection method.</param>
/// <param name="mi">A MethodInfo object.</param>
public SyncReflectionSink(object instance, MethodInfo mi) : base(instance, mi) {}
/// <summary>
/// Invoke the synchronous event handler as determined by the reflection information.
/// </summary>
/// <param name="sender">The originator of the event.</param>
/// <param name="args">Any parameters passed to the event.</param>
/// <returns>This method always returns a null because the event is invoked synchronously.</returns>
public override IAsyncResult Invoke(object sender, object[] args)
{
try
{
mi.Invoke(instance, bindingFlags, null, new object[] {sender, new EventArgs(args)}, null);
}
catch (Exception e)
{
Dbg.Warn(false, new DbgKey("EvMgrInvokeError"), e.ToString());
}
return null;
}
}
/// <summary>
/// AsyncEvent handles the asynchronous invocation of events bound using an event delegate.
/// </summary>
public class AsyncEventHandlerSink : EventHandlerSink
{
/// <summary>
/// Constructor.
/// </summary>
/// <param name="eh">The method that will handle the event.</param>
public AsyncEventHandlerSink(System.EventHandler eh) : base(eh) {}
/// <summary>
/// Invoke the asynchronous event handler as declared by the delegate.
/// </summary>
/// <param name="sender">The originator of the event.</param>
/// <param name="args">Any parameters passed to the event.</param>
/// <returns>This method always returns an IAsyncResult.</returns>
public override IAsyncResult Invoke(object sender, object[] args)
{
IAsyncResult res=null;
try
{
res=eh.BeginInvoke(sender, new EventArgs(args), null, null);
}
catch (Exception e)
{
Dbg.Warn(false, new DbgKey("EvMgrInvokeError"), e.ToString());
}
return res;
}
}
/// <summary>
/// ReflectionAsyncEvent handles the asynchronous invocation of events bound by reflection.
/// </summary>
public class AsyncReflectionSink : ReflectionSink
{
/// <summary>
/// References our internal asynchronous method. This is necessary so that we can
/// invoke the reflection method asynchronously.
/// </summary>
private delegate void RunAsync(object sender, object[] args);
private RunAsync run;
/// <summary>
/// Constructor.
/// </summary>
/// <param name="mi">A MethodInfo object.</param>
public AsyncReflectionSink(MethodInfo mi) : base(mi)
{
InitializeAsyncDelegate();
}
/// <summary>
/// Constructor.
/// </summary>
/// <param name="instance">The instance associated with the reflection method.</param>
/// <param name="mi">A MethodInfo object.</param>
public AsyncReflectionSink(object instance, MethodInfo mi) : base(instance, mi)
{
InitializeAsyncDelegate();
}
/// <summary>
/// Instantiates the delegate for the asynchronous handler.
/// </summary>
private void InitializeAsyncDelegate()
{
run=new RunAsync(Run);
}
/// <summary>
/// Invokes the reflection method asynchronously.
/// </summary>
/// <param name="sender">The originator of the event.</param>
/// <param name="args">Any parameters passed to the handler.</param>
/// <returns>This method always returns an IAsyncResult object.</returns>
public override IAsyncResult Invoke(object sender, object[] args)
{
return run.BeginInvoke(sender, args, null, new Object());
}
/// <summary>
/// This method is invoked asynchronously and invokes the reflection method.
/// </summary>
/// <param name="sender"></param>
/// <param name="args"></param>
private void Run(object sender, object[] args)
{
try
{
mi.Invoke(instance, bindingFlags, null, new object[] {sender, new EventArgs(args)}, null);
}
catch (Exception e)
{
Dbg.Warn(false, new DbgKey("EvMgrInvokeError"), e.ToString());
}
}
}
/// <summary>
/// A very thin wrapper for the collection of event handlers.
/// </summary>
public class EventCollection : SortedList
{
}
/// <summary>
/// A singleton class. Manages the invocation of synchronous, asynchronous, delegate and reflect bound
/// event handlers.
/// </summary>
public class EventManager
{
static EventCollection evList=new EventCollection();
/// <summary>
/// Initializes internal data structures.
/// </summary>
public static void Initialize()
{
Dbg.Problems.Add(new DbgKey("EvMgrInvokeError"),
"Cannot invoke event.",
new String[] {
"A system-wide error has occurred."});
Dbg.Problems.Add(new DbgKey("EvMgrNoEvent"),
"Missing event.",
new String[] {
"The specified event does not exist in the event manager event collection."});
Dbg.Problems.Add(new DbgKey("EvMgrNoMethod"),
"Unable to locate method.",
new String[] {
"The assembly could not be found.",
"The method type does not exist.",
"The method itself could not be found."});
}
/// <summary>
/// Adds a synchronous event handler to the event collection.
/// </summary>
/// <param name="name">The event name. This is NOT the method name, but a abstract label for referencing the event later.</param>
/// <param name="eh">The method that handles the event. Using the EventHandler delegate, both static and non-static methods may be specified.</param>
public static void AddSyncEventSink(string name, System.EventHandler eh)
{
evList.Add(name, new SyncEventHandlerSink(eh));
}
/// <summary>
/// Adds an asynchronous event handler to the event collection.
/// </summary>
/// <param name="name">The event name. This is NOT the method name, but a abstract label for referencing the event later.</param>
/// <param name="eh">The method that handles the event. Using the EventHandler delegate, both static and non-static methods may be specified.</param>
public static void AddAsyncEventSink(string name, System.EventHandler eh)
{
evList.Add(name, new AsyncEventHandlerSink(eh));
}
/// <summary>
/// Adds a synchronous static event handler to the event collection using reflection.
/// </summary>
/// <param name="name">The event name. This is NOT the method name, but a abstract label for referencing the event later.</param>
/// <param name="reflection">The reflected method name. This must be in the format: "assembly/namespace.class/method"</param>
public static void AddSyncEventSink(string name, string reflection)
{
MethodInfo mi=GetMethodInfo(reflection);
if (mi!=null)
{
evList.Add(name, new SyncReflectionSink(mi));
}
}
/// <summary>
/// Adds a synchronous instantiated event to the event collection using reflection.
/// </summary>
/// <param name="name">The event name. This is NOT the method name, but a abstract label for referencing the event later.</param>
/// <param name="instance">The instance containing the specified reflected method.</param>
/// <param name="reflection">The reflected method name. This must be in the format: "assembly/namespace.class/method"</param>
public static void AddSyncEventSink(string name, object instance, string reflection)
{
MethodInfo mi=GetMethodInfo(reflection);
if (mi!=null)
{
evList.Add(name, new SyncReflectionSink(instance, mi));
}
}
/// <summary>
/// Adds an asynchronous static event handler to the event collection using reflection.
/// </summary>
/// <param name="name">The event name. This is NOT the method name, but a abstract label for referencing the event later.</param>
/// <param name="reflection">The reflected method name. This must be in the format: "assembly/namespace.class/method"</param>
public static void AddAsyncEventSink(string name, string reflection)
{
MethodInfo mi=GetMethodInfo(reflection);
if (mi!=null)
{
evList.Add(name, new AsyncReflectionSink(mi));
}
}
/// <summary>
/// Adds a synchronous instantiated event to the event collection using reflection.
/// </summary>
/// <param name="name">The event name. This is NOT the method name, but a abstract label for referencing the event later.</param>
/// <param name="instance">The instance containing the specified reflected method.</param>
/// <param name="reflection">The reflected method name. This must be in the format: "assembly/namespace.class/method"</param>
public static void AddAsyncEventSink(string name, object instance, string reflection)
{
MethodInfo mi=GetMethodInfo(reflection);
if (mi!=null)
{
evList.Add(name, new AsyncReflectionSink(instance, mi));
}
}
/// <summary>
/// Invoke an event.
/// </summary>
/// <param name="name">The abstract event name.</param>
/// <returns>For synchronous events, returns null, otherwise returns an IAsyncResult object.</returns>
public static IAsyncResult Invoke(string name)
{
return Invoke(name, null, null);
}
/// <summary>
/// Invoke an event.
/// </summary>
/// <param name="name">The abstract event name.</param>
/// <param name="sender">The instance of the sender.</param>
/// <returns>For synchronous events, returns null, otherwise returns an IAsyncResult object.</returns>
public static IAsyncResult Invoke(string name, object sender)
{
return Invoke(name, sender, null);
}
/// <summary>
/// Invoke an event.
/// </summary>
/// <param name="name">The abstract event name.</param>
/// <param name="args">A list of parameters passed to the event handler.</param>
/// <returns>For synchronous events, returns null, otherwise returns an IAsyncResult object.</returns>
public static IAsyncResult Invoke(string name, object[] args)
{
return Invoke(name, null, args);
}
/// <summary>
/// Invoke an event.
/// </summary>
/// <param name="name">The abstract event name.</param>
/// <param name="sender">The instance of the sender.</param>
/// <param name="args">A list of parameters passed to the event handler.</param>
/// <returns>For synchronous events, returns null, otherwise returns an IAsyncResult object.</returns>
public static IAsyncResult Invoke(string name, object sender, object[] args)
{
IAsyncResult res=null;
if (evList.Contains(name))
{
Dbg.WriteLine("EventManager.Invoke: "+name);
res=((EventSink)evList[name]).Invoke(sender, args);
}
else
{
Dbg.Warn(false, new DbgKey("EvMgrNoEvent"), name);
}
return res;
}
/// <summary>
/// Returns a MethodInfo object with the parsed reflect string.
/// </summary>
/// <param name="reflection">A reflection method name, in the format "assembly/namespace.class/method".</param>
/// <returns></returns>
private static MethodInfo GetMethodInfo(string reflection)
{
MethodInfo mi=null;
try
{
string[] info=reflection.Split(new char[] {'/'});
Assembly mainAssembly=Assembly.LoadFrom(info[0]);
Type[] types=mainAssembly.GetTypes();
Type type=mainAssembly.GetType(info[1]);
MethodInfo[] mis=type.GetMethods();
mi=type.GetMethod(info[2]);
}
catch (Exception e)
{
Dbg.Warn(false, new DbgKey("EvMgrNoMethod"), e.ToString()+"\n"+"Method:"+reflection);
}
return mi;
}
}
}