将事件处理程序附加到在运行时使用未知类型参数的反射初始化的泛型类型

时间:2013-01-29 10:43:55

标签: c# reflection delegates event-handling generic-programming

请查看下面的代码,该代码基于您拥有控制器类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 个答案:

答案 0 :(得分:2)

通常,您应该能够添加事件处理程序,如下所示:

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

但是,您应该将OnCompleted委托定义移到课堂外,以便能够在不知道T的{​​{1}}的情况下引用它。

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

答案 1 :(得分:0)

答案 2 :(得分: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;

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

答案 3 :(得分:0)

Lats说你有 eventName handlerMethodName objectOnWhichTheEventIsDefined objectOnWhichTheEventHandlerIsDefined eventName handlerMethodName 是字符串,其余对象是对象数据类型。然后,您可以使用反射处理事件与处理程序,如下所示。

Object.create

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

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