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>基本上应该消耗掉一切。我不希望他们也使用值类型。

用 C#4 没问题,但现在我用 C#3 做这些事情,只是用接口假装逆变:

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

好吧,现在,我想像这样将数据打包成“事件类型”。该事件的通用参数必须是协变的。

SubX : ISubscriber<DataChanged<A>>

DataChanged<T>
  T Data {get;}

当我发布Publish<DataChanged<B>>(new DataChanged<B>(new B())(给定 B:A)时,应通知订阅者DataChanged<A>Data 是传递给的 B 实例的位置DataChanged<B>。所以我也需要协方差支持。

我想编写一个支持 Co-/和逆变的库,如下所示:

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

这将允许像这样的转换(不是强制转换!):

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

你怎么看?可能吗?考虑使用动态代理来做这件事。

4

2 回答 2

1

IMO,这会让事情很快变得非常复杂,这意味着你最终会编写很多反射代码。你能等到 C# 4.0 吗?;-p

或者,您的代码可以忽略它不知道如何处理的事情......

于 2009-04-01T22:10:55.360 回答
1

在这部分:

当我发布 Publish<DataChanged<B>>(new DataChanged<B>(new B())时, Subscriber应该通知 -instance在 DataChanged<A>哪里。.DataB

我可能没听懂你——.Data比如我看不到指的是什么,我只能猜测 B 和 A 之间的关系。你的意思是 B 是从 A 派生的吗?

如果是这样,C# 4 不一定会让这样的事情自动发生。默认情况下,类型X<A>X<B>根本不兼容。如果X是一个interface并且类型参数被标记为out,那么X<B>可以分配给一个类型的变量X<A>。但请注意,这仅适用于接口,而不适用于具体类型(委托也有类似的规定,仅此而已)。

编辑:

因此,您要做的是模拟X<B>可以分配给X<A>C#/CLR 4.0 中类型变量的方式,其中 X 是一个接口。

假设 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);
    }
}

您只需将每个方法转发到真正的实现。

但是,对于泛型外部类和通过继承相关的泛型参数对的每种可能组合,您都需要这样的包装类。手动编写它们并保持大量查找以针对给定情况选择正确的任务将是一项乏味,容易出错且永远无法完成的任务。

所以现在您进入代码生成以在运行时制造包装类。

于 2009-04-01T22:28:23.120 回答