0

请看下面的代码,这是基于你有一个控制器类 Controller 的假设。它是一个具有约束 CGeneric 的泛型类,其中 T:IRecord、两个具体的记录类 CRecordCustomer:IRecord 和 CRecordVipCustomer:Irecord。问题是如何在运行前不知道 t 类型的情况下将事件处理程序附加到泛型类型?

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 );
}
4

4 回答 4

2

通常,您应该能够按如下方式添加事件处理程序:

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

但是,您应该将您的OnCompleted委托定义移到类之外,以便能够在不知道的情况下引用TCGeneric<T>

(注意:您的示例代码有很多其他错误会阻止您编译它)

于 2013-01-29T11:16:02.177 回答
0

一个解决方案可能是这样的:

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()
    {

    }
}

并且可以通过这种方式实例化:

    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;

而且它不依赖于泛型类型。

于 2013-01-29T11:37:16.587 回答
0

如果我理解你的正确,这可以帮助你http://www.codeproject.com/Articles/121923/Using-Reflection-to-Manage-Event-Handlers

于 2013-01-29T11:02:12.307 回答
0

Lats 说你有eventNamehandlerMethodNameobjectOnWhichTheEventIsDefinedobjectOnWhichTheEventHandlerIsDefinedeventNamehandlerMethodName是字符串,其余的对象是对象数据类型。然后,您可以使用反射将事件与处理程序连接起来,如下所示。

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;
    }
}

一个完整的控制台示例如下所示。

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.");
    }
}
于 2017-08-05T10:12:11.573 回答