Динамическое обобщение интерфейса - PullRequest
1 голос
/ 08 апреля 2011

Я хочу динамически обнаруживать и регистрировать реализации интерфейса. Ради аргумента у меня есть два метода, подобных этим:

public void Register<TEvent>(IHandler<TEvent> handler) where TEvent : IEvent

public void Register<TEvent>(Action<TEvent> action) where TEvent : IEvent
{
    Register<TEvent>(handler.Handle);
}

И интерфейсы похожи на следующие:

public interface IHandler<T> where T : IEvent
{
    void Handle(T args);
}

public interface IEvent
{
}

Тогда у меня есть конкретные реализации, такие как:

public class ChangedEvent : IEvent
{...}

public class ChangedHandler : IHandler<ChangedEvent>
{
    public void Handle(ChangedEvent args)
    {

    }
}

Затем я могу обнаружить все конкретные реализации IHandler <> в моих сборках, и я хотел сделать что-то вроде этого:

IList<Type> types = TypeFinder.GetImplementors(typeof(IHandler<>));
foreach (Type type in types)
{
    object instance = Activator.CreateInstance(type);
    Listeners.Register((IHandler<IEvent>)instance);
}

Код скомпилируется, он не является недействительным, но во время выполнения приведение не выполняется, потому что оно недопустимо. Однако, если я приведу к конкретному IEvent, как:

IList<Type> types = TypeFinder.GetImplementors(typeof(IHandler<>));
foreach (Type type in types)
{
    object instance = Activator.CreateInstance(type);
    Listeners.Register((IHandler<ChangedEvent>)instance);
}

Это приведение действительно, и оно будет запущено. Проблема заключается в динамике сценария, я хочу иметь возможность обнаруживать типы и регистрировать их. Я не хотел создавать не универсальный интерфейс для обработчика, но я полагаю, что это невозможный сценарий, потому что среда не имеет достаточно информации для вывода требуемых типов. Есть ли способ достичь этого, или у вас есть какие-либо предложения для достижения желаемого результата?

Большое спасибо.

Ответы [ 3 ]

1 голос
/ 08 апреля 2011

Это не работает из-за Ковариантности и контравариантности , представьте, что это сработало, и вы сделали следующее.

public class AnotherTypeOfEvent : IEvent      {...} 

public void Register<TEvent>(IHandler<TEvent> handler) where TEvent : IEvent 
{
    //Really our runtime type expects ChangedEvent, but our constraint is
    //only for IEvent so you could do this - oh dear..
    handler.Handle(new AnotherTypeOfEvent());     
}

Listeners.Register((IHandler<IEvent>)new ChangedHandler());   

Вы передадите AnotherTypeOfEvent в свой метод ChangedHandler.Handle, который явно ожидает ChangedEvent, это вызовет всевозможные проблемы.

0 голосов
/ 08 апреля 2011

Почему вы не указываете в typefinder тип, который вы хотите получить, как вы будете приводить его после?

IList<Type> types = TypeFinder.GetImplementors(typeof(IHandler<IEvent>));
foreach (Type type in types)
{
    object instance = Activator.CreateInstance(type);
    Listeners.Register((IHandler<IEvent>)instance);
}
0 голосов
/ 08 апреля 2011

Я не уверен, какую ошибку вы получаете. Это хорошо для меня:

public interface IEvent
{

}

public interface IHandler<T>
{

}

public class Test //: ITest
{
    public void Register<TEvent>(IHandler<TEvent> handler) where TEvent : IEvent
    {

    }
}

public class ChangedEvent : IEvent
{


}
public class Example
{
    public static void Main()
    {
        Test t = new Test();
        Type[] types = new Type[10];
        foreach (Type type in types)
        {
            object instance = Activator.CreateInstance(type);
            t.Register((IHandler<IEvent>)instance);
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...