Есть ли более элегантный способ сделать это в .NET 4.0? - PullRequest
1 голос
/ 10 ноября 2010

Похоже, что C # 4.0 не поддерживает ковариацию (используя ключевое слово "in") для параметров в переопределениях; это тот случай?

Если так, есть ли более элегантный способ сделать это?

КОНТЕКСТ

public interface IBaseEvent { /* ... */ }

public interface IDerivedEvent : IBaseEvent { /* ... */ }

public class MoreDerivedEvent : IDerivedEvent { /* ... */ }

У меня есть набор классов, которые обрабатывают MoreDerivedEvent. Из-за ограничений кода обработки событий я могу зарегистрировать только один обработчик событий для MoreDerivedEvent, и я не знаю, будет ли он обрабатывать регистрацию интерфейсов как события (я не верю, что так будет, поскольку использовать классы явно). Итак, чтобы правильно обработать событие, я определил обработчики следующим образом:

public class BaseType
{
    protected virtual void Handle(IBaseEvent @event) { /* Do Base Stuff */ }
}

public class DerivedType
{
    protected virtual void Handle(IDerivedEvent @event)
    {
        /* Do Derived Stuff */
        Handle((IBaseEvent)@event);
    }

    protected override sealed void Handle(IBaseEvent @event)
    {
        base.Handle(@event);
    }
}

Это, очевидно, не обеспечивает истинного наследования, и я, вероятно, просто сгладю типы, полученные из DerivedType и BaseType, если не смогу решить эту проблему. Но я решила, что сначала добавлю это в сообщество Stack Overflow.

Ответы [ 2 ]

7 голосов
/ 10 ноября 2010

Во-первых, ковариация типа параметра не безопасна .Предположим, мы допустили ковариацию типа параметра:

class B 
{
    public virtual void Frob(Animal a)
    {
    }
}
class D : B
{
    public override void Frob(Giraffe g)
    {
    }
}
....
B b = new D();
b.Frob(new Tiger());  // Calls D.Frob, which takes a giraffe.

Нет, ковариация совсем не то, что вам нужно.Это небезопасно.Требуется ковариация для типов возврата , а не для типов параметров .Для типов параметров вы хотите Контравариантность :

class B 
{
    public virtual void Frob(Giraffe g)
    {
    }
}
class D : B
{
    public override void Frob(Animal a)
    {
    }
}
....
B b = new D();
b.Frob(new Giraffe());  // Calls D.Frob, which takes any animal.

Никаких проблем там нет.

К сожалению, C # не поддерживает ни ковариацию типа возвращаемого значения, ни контравариантность типа параметра.Извините!

2 голосов
/ 10 ноября 2010

Для начала вам необходим интерфейс для указания контрастности на

public interface IBaseHandler<in T> where T : IBaseEvent
{
    void Handle(T handle);
}

Затем вы можете определить базовый класс для выполнения «базовых вещей»

public class BaseType<T> : IBaseHandler<T> where T : IBaseEvent
{
    public virtual void Handle(T handle) { /* do base stuff */} 
}

, который затем позволит вам переопределить для MoreDerivedEvent

public class MoreDerivedType : BaseType<MoreDerivedEvent>
{
    public override void Handle(MoreDerivedEvent handle)
    {
        base.Handle(handle);
    }
}
...