2009-04-01 4 views
0

В моем приложении я создаю простой хаб событий, который предлагает что-то для регистрирующих абонентов:Должен ли я поддерживать Co/Contravariance для Pub-/Sub-Scenarios в C# 3.0?

Subscribes<EventType>(ISubscriber<EventType> subscriber) 
// and some other methods for adding subscribers 

И для публикации событий.

Publish<EventType>(EventType @event) 

Довольно просто. Я хочу направить Publish<int>(0) всем подписчикам, использующим ISubscriber<int>.

Что не так сложно, что я хочу, чтобы подписчики EventType были контравариантными. Поэтому ISubscriber<object> должен в основном потреблять все. Я не хочу, чтобы они тоже потребляли ценности.

С # 4, что нет проблем, но сейчас я делаю это вещество с C# 3 и просто притворяюсь контравариация с интерфейсом:

public interface IContravariantGenerics { 
    object AsVariantFor(Type[] genericParamters); 
} 

Ну вот, теперь, я хочу Empack данных в «типы событий», подобные этому. Общие параметры этих событий должны быть ковариантными.

SubX : ISubscriber<DataChanged<A>> 

DataChanged<T> 
    T Data {get;} 

Когда я опубликовать Publish<DataChanged<B>>(new DataChanged<B>(new B()) (с учетом B: А), Абонент должен быть уведомлен с DataChanged<A> где данные В-экземпляр передается DataChanged<B>. Поэтому мне нужна ковариантная поддержка.

Я думал о написании LIB, который поддерживает как СО-/и контрвариацию так:

IMyObject<T1, T2> : IWithVariance<In, Out> 

который позволил бы преобразования (не бросает!), Как это:

Obj<Fruit, Fruit> x; 
IMyObject<Apple, object> x2 = x.ToVariant<Apple, object>(); 

Что вас думать? Является ли это возможным? Мысль о том, чтобы делать это с помощью динамических прокси.

ответ

1

IMO, это очень быстро сделает вещи очень сложными, и это будет означать, что вы в конечном итоге написали много кода отражения. Можете ли вы ждать C# 4.0? ;-p

Кроме того, ваш код может просто игнорировать вещи, он не знает, как обращаться с ...

+0

Правильно, я должен был бы принимать вещи здесь и там. В случае неоднозначности мне пришлось бы бросать исключения. –

1

В этой части:

Когда я публикую Publish<DataChanged<B>>(new DataChanged<B>(new B()), то Subscriber должен Оформить заявку на уведомление DataChanged<A>, где .Data является B -instance.

Я не понял тебя - я не могу видеть, что .Data относится, например, и я могу только догадываться, на отношения между B и A. Вы имеете в виду, что B является производным от А?

Если это так, C# 4 не обязательно приведет к тому, что такое произойдет автоматически. Типы X<A> и X<B> по умолчанию несовместимы. Если X является interface, а параметр типа помечен как out, то X<B> может быть присвоен переменной типа X<A>.Но учтите, что это только для интерфейсов, а не для конкретных типов (для делегатов есть аналогичное положение, но это все).

Edit:

И поэтому то, что вы хотите сделать, это имитировать способ, которым X<B> может быть присвоено переменной типа X<A> в C#/CLR 4.0, где X представляет собой интерфейс.

Пусть Х:

interface X<T> 
{ 
    T Foo(int arg); 

    // Note: T may only appear as an output, so this is illegal: 
    // void Foo(T arg); 
} 

У вас есть X<B>, вам нужно X<A>. Вы знаете, что B назначается A. Поэтому вам нужен следующий адаптер:

class WrapX_A_B : X<A> 
{ 
    public X<B> Impl { get; set; } 

    public A Foo(int arg) 
    { 
     return Impl.Foo(arg); 
    } 
} 

Вы просто пересылаете каждый метод на реальную реализацию.

Однако вам понадобится такой класс-оболочка для каждой возможной комбинации общих внешних классов и пар общих параметров, связанных с наследованием. Было бы утомительной, подверженной ошибкам и никогда не завершенной задачей писать все вручную и поддерживать большой поиск, чтобы выбрать правильный для данной ситуации.

Итак, теперь вы создаете код для создания классов-оболочек во время выполнения.

+0

Вы правы. Исправил вопрос. В C# 4 я бы получил ISubscriber и IChangedEvent . –

+0

См. Обновление выше. –

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

  • Нет связанных вопросов^_^