2010-11-10 5 views
1

Похоже, что C# 4.0 не поддерживает ковариацию (используя ключевое слово «in») по параметрам в переопределениях; что дело?Есть ли более элегантный способ сделать это в .NET 4.0?

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

КОНТЕКСТ

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, если я не может решить эту проблему. Но я решил, что сначала поставлю его в сообщество переполнения стека.

ответ

7

Прежде всего, ковариация параметров параметров - not typesafe. Предположим, что мы позволили типа параметра ковариации:

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# не поддерживает ковариацию возвращаемого типа и не противоречит параметрическому типу параметров. Сожалею!

+0

Спасибо за исправление в сравнении с контравариантностью; Я обновил вопрос и теги. – arootbeer

2

Сначала вам нужно интерфейс, чтобы указать противопоказания дисперсии на

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); 
    } 
} 
+0

+1 - это интересный подход. В этом случае я не предпочитаю этого, потому что он вводит интерфейс, который в противном случае не будет использоваться, и по определению мои защищенные методы станут общедоступными. – arootbeer

Смежные вопросы