0

Please have a look at code below, which is based on the assumption that you have a controller class Controller. It is a generic class with constraint CGeneric where T:IRecord, two concrete record classes CRecordCustomer:IRecord, and CRecordVipCustomer:Irecord. The question is how to attach event handler to a generic type without knowing type of t before runtime?

public class CGeneric<T> where T:IRecord, new()
{
public delegate void OnCompleted();
public event OnCompleted completed;

private void ProcessStuff(T ConcreteRecordType)
{
    T concreteInstance = default(T);
    (concreteInstance as T).DoSomeInterfaceStuff();
    if(this.completed !=null)
    {
        this.completed;
    }
}
}

// This is how the controller class instantiates CGeneric<T> 
// Using reflection gets all types that implement IRecord
// Then using one of those types (which is unknown at compile time):

class Controller
{

Type[] allTypes = Assembly.GetExecutingAssembly().GetTypes();

    Type concreteType allTypes.Where(t => t.GetInterfaces().Contains(typeof(IRecord)) &&      !IgnoreType(t)).ToList()[0];


    Type genericType = typeof(CGeneric<>);

    genericType = genericType .MakeGenericType(
    ConstructorInfo constructor = genericType .GetConstructor(new Type[] { });
    Object genericInstance = constructor.Invoke(new Object[] { });

//This is where I need to hook to OnCompletedEvent

    MethodInfo processmoethod = genericType .GetMethod("Process");

    processmoethod.Invoke(genericInstance , concreteType );
}
Hamlet Hakobyan
  • 32,965
  • 6
  • 52
  • 68
moral
  • 150
  • 1
  • 6

4 Answers4

2

Normally, you should be able to add an event handler as follows:

OnCompleted handler = () => { /*event handler*/ };
genericType.GetEvent("completed").AddEventHandler(genericInstance, handler);

However, you should move your OnCompleted delegate definition outside the class in order to be able to reference it without knowing the T of CGeneric<T>.

(Note: your sample code has a lot of other errors that will prevent you from compiling it)

Eren Ersönmez
  • 38,383
  • 7
  • 71
  • 92
0

If I understood you corret, this can help you http://www.codeproject.com/Articles/121923/Using-Reflection-to-Manage-Event-Handlers

Alex
  • 8,827
  • 3
  • 42
  • 58
0

A solution may be this:

public delegate void OnCompleted();

public interface IRecord
{
    void DoSomeInterfaceStuff();
    event OnCompleted completed;
}

public interface IEvents
{
    event OnCompleted completed;
}

public class CGeneric<T> : IEvents
    where T:IRecord, new()
{
    public event OnCompleted completed;
    private void ProcessStuff(T ConcreteRecordType)
    {
        T concreteInstance = default(T);

        concreteInstance.DoSomeInterfaceStuff();

        if(this.completed !=null)
        {
            this.completed();
        }
    }
}

public class Record : IRecord
{
    public void DoSomeInterfaceStuff()
    {

    }
}

And could be instantiated in this way:

    Type toInstantiate = Type.GetType("CGeneric`1");
    Type[] parameters = new Type[] { typeof(Record) };
    Type instantiated = toInstantiate.MakeGenericType(parameters);

    IEvents result = Activator.CreateInstance(instantiated) as IEvents;
    result.completed += result_completed;

And it's not dependent on the generic type.

lucabc
  • 1
  • 1
0

Lats say you have the eventName, handlerMethodName, objectOnWhichTheEventIsDefined, objectOnWhichTheEventHandlerIsDefined. The eventName and handlerMethodName are strings and the rest of the objects are of object data type. Then you can wire up the event with a handler using reflection as follows.

public bool SubscribeEvent(string eventName, string handlerMethodName, 
    object objectOnWhichTheEventIsDefined, 
    object objectOnWhichTheEventHandlerIsDefined)
{
    try
    {
        var eventInfo = objectOnWhichTheEventIsDefined.GetType().GetEvent(eventName);
        var methodInfo = objectOnWhichTheEventHandlerIsDefined.GetType().
        GetMethod(handlerMethodName);

        // Create new delegate mapping event to handler
        Delegate handler = Delegate.CreateDelegate(eventInfo.EventHandlerType, objectOnWhichTheEventHandlerIsDefined, methodInfo);
        eventInfo.AddEventHandler(objectOnWhichTheEventIsDefined, handler);
        return true;
    }
    catch (Exception ex)
    {
        // Log failure!
        var message = "Exception while subscribing to handler. Event:" + eventName + " - Handler: " + handlerMethodName + "- Exception: " + ex;
        Debug.Print(message);
        return false;
    }
}

A full console example would look like this.

class Program
{
    static void Main(string[] args)
    {
        var typeWithEvent = new TypeWithEvent();
        var typeWithEventHandler = new TypeWithEventHandler();

        SubscribeEvent("EventTest", "EventHandlerMethod", typeWithEvent, typeWithEventHandler);

        EventArgs e = new EventArgs();
        Console.WriteLine("Event is about to be raised.");
        typeWithEvent.OnTimeToRaiseTheEvent(e);
        Console.WriteLine("Event trigger is completed.");
        Console.ReadLine();
    }
    static bool SubscribeEvent(string eventName, string handlerMethodName, object objectOnWhichTheEventIsDefined, object objectOnWhichTheEventHandlerIsDefined)
    {
        try
        {
            var eventInfo = objectOnWhichTheEventIsDefined.GetType().GetEvent(eventName);
            var methodInfo = objectOnWhichTheEventHandlerIsDefined.GetType().
            GetMethod(handlerMethodName);

            // Create new delegate mapping event to handler
            Delegate handler = Delegate.CreateDelegate(eventInfo.EventHandlerType, objectOnWhichTheEventHandlerIsDefined, methodInfo);
            eventInfo.AddEventHandler(objectOnWhichTheEventIsDefined, handler);
            return true;
        }
        catch (Exception ex)
        {
            // Log failure!
            var message = "Exception while subscribing to handler. Event:" + eventName + " - Handler: " + handlerMethodName + "- Exception: " + ex;
            Debug.Print(message);
            return false;
        }
    }
}
internal class TypeWithEvent
{
    public event EventHandler<EventArgs> EventTest;
    internal void OnTimeToRaiseTheEvent(EventArgs e)
    {
        // Thread safe way to raise event as described in Events chapter 11 of
        // the book CLR Via C#, 4th Edition, by Jeffrey Richter
        EventHandler<EventArgs> temp = Volatile.Read(ref EventTest);
        if (temp != null) temp(this, e);
    }
}

internal class TypeWithEventHandler
{
    public void EventHandlerMethod(Object sender, EventArgs e)
    {
        Console.WriteLine("From the event handler method.");
    }
}
VivekDev
  • 20,868
  • 27
  • 132
  • 202