Прилагая обработчик событий к универсальному типу, инициализированному, используя отражение во времени выполнения с неизвестным параметром типа

Пожалуйста, взгляните на код ниже, который основан на предположении, что у вас есть Диспетчер класса контроллера. Это - универсальный класс с ограничением CGeneric, где T:IRecord, два бетона делают запись классов CRecordCustomer:IRecord и CRecordVipCustomer:Irecord. Вопрос состоит в том, как приложить обработчик событий к универсальному типу, не зная тип t перед временем выполнения?

public class CGeneric 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 
// 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 );
}
0
nl ja de
Вы попытались собрать этот код?
добавлено автор Hamlet Hakobyan, источник

4 ответы

Обычно, необходимо быть в состоянии добавить обработчик событий следующим образом:

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.

(Примечание: у вашего примера кода есть много других ошибок, которые будут препятствовать тому, чтобы вы собрали его),

2
добавлено

Латы говорят, что у вас есть eventName , handlerMethodName , objectOnWhichTheEventIsDefined , objectOnWhichTheEventHandlerIsDefined . <Сильные> eventName и handlerMethodName являются последовательностями, и остальная часть объектов имеют тип данных Object. Тогда можно обеспечить электричеством событие с помощью укладчика, использующего отражение следующим образом.

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 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 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.");
    }
}
0
добавлено
0
добавлено

Решение может быть этим:

public delegate void OnCompleted();

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

public interface IEvents
{
    event OnCompleted completed;
}

public class CGeneric : 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;

И это не зависит от универсального типа.

0
добавлено
Microsoft Stack Jobs
Microsoft Stack Jobs
1 788 участник(ов)

Work & freelance only Microsoft Stack. Feed https://t.me/Microsoftstackjobsfeed Чат про F#: @Fsharp_chat Чат про C#: @CSharpChat Чат про Xamarin: @xamarin_russia Чат общения:@dotnettalks

Microsoft Developer Community Chat
Microsoft Developer Community Chat
584 участник(ов)

Чат для разработчиков и системных администраторов Microsoft Developer Community. __________ Новостной канал: @msdevru __________ Баним за: оскорбления, мат, рекламу, флуд, флейм, спам, NSFW контент, а также большое количество оффтоп тем. @banofbot