In my application I am creating a simple event hub that offers something for registering subscribers:
Subscribes<EventType>(ISubscriber<EventType> subscriber)
// and some other methods for adding subscribers
And for publishing events.
Publish<EventType>(EventType @event)
Quite simple. I want to route Publish<int>(0) to all subscribers implementing ISubscriber<int>.
What's not too hard is, that I want the subscribers EventType to be contravariant. So ISubscriber<object> should basically consume everything. Not shure wether I want them to consume valuetypes, too.
With C#4 that is no problem, but now I'm doing this stuff with C#3 and just faking contravariance with an interface:
public interface IContravariantGenerics {
object AsVariantFor(Type[] genericParamters);
}
Well, now, I want to empack data into "event types" like this. The generic parameters of that events must be covariant.
SubX : ISubscriber<DataChanged<A>>
DataChanged<T>
T Data {get;}
When I publish Publish<DataChanged<B>>(new DataChanged<B>(new B()) (given B : A), the Subscriber should be notified with DataChanged<A> where Data is the B-instance passed to DataChanged<B>. So I need covariance support as well.
I thought of writing a lib that supports both Co-/And Contravariance like this:
IMyObject<T1, T2> : IWithVariance<In, Out>
Which would allow conversions (not casts!) like this:
When I publish Publish<DataChanged<B>>(new
DataChanged<B>(new B()), the Subscriber should be notified with DataChanged<A> where .Data is the B-instance.
I may not have understood you - I can't see what .Data refers to, for example, and I can only guess at the relationship between B and A. Do you mean that B is derived from A?
If so, C# 4 will not necessarily make such a thing happen automatically. The types X<A> and X<B> are not compatible at all by default. If X is an interface and the type parameter is marked as out, then X<B> can be assigned to a variable of type X<A>. But note that this is for interfaces only, not concrete types (there is a similar provision for delegates, but that's all).
Edit:
So therefore what you want to do is simulate the way that X<B> can be assigned to a variable of type X<A> in C#/CLR 4.0, where X is an interface.
Suppose X is:
interface X<T>
{
T Foo(int arg);
// Note: T may only appear as an output, so this is illegal:
// void Foo(T arg);
}
You have an X<B>, you need an X<A>. You know that B is assignable to A. So you need the following adaptor:
class WrapX_A_B : X<A>
{
public X<B> Impl { get; set; }
public A Foo(int arg)
{
return Impl.Foo(arg);
}
}
You just forward each method on to the real implementation.
However, you would need such a wrapper class for every possible combination of generic outer classes and pairs of generic parameters related by inheritance. It would be a tedious, error-prone and never-complete task to write them all by hand and maintain a big lookup to pick the right one for a given situation.
So now you're into code generation to manufacture the wrapper classes at runtime.
发布评论
评论(2)
IMO,这将使事情很快变得非常复杂,这意味着您最终会编写大量反射代码。 你能等待 C# 4.0 吗? ;-p
或者,您的代码可以忽略它不知道如何处理的事情...
IMO, this will make things very complex very quickly, and it'll mean you end up writing a lot of reflection code. Can you wait for C# 4.0? ;-p
Alternatively, your code could just ignore things it doesn't know how to handle...
在这一部分中:
我可能没有理解你的意思 - 例如,我看不到
.Data
指的是什么,我只能猜测 B 和 A 之间的关系。你的意思是 B 是从 A 派生的吗?如果是这样,C# 4 不一定会让这样的事情自动发生。 默认情况下,类型
X
和X
根本不兼容。 如果X
是一个接口
并且类型参数被标记为out
,那么X
可以被赋值到X
类型的变量。 但请注意,这仅适用于接口,而不适用于具体类型(对于委托也有类似的规定,但仅此而已)。
编辑:
因此,您想要做的是模拟将
X
分配给X
类型的变量的方式> 在 C#/CLR 4.0 中,其中 X 是接口。假设 X 是:
您有一个
X
,您需要一个X
。 您知道B
可分配给A
。 因此,您需要以下适配器:您只需将每个方法转发到真正的实现即可。
但是,对于通用外部类和通过继承相关的通用参数对的每种可能的组合,您都需要这样的包装类。 手动编写所有这些内容并进行大量查找以针对给定情况选择正确的内容将是一项乏味、容易出错且永远无法完成的任务。
现在您需要生成代码以在运行时制造包装器类。
In this part:
I may not have understood you - I can't see what
.Data
refers to, for example, and I can only guess at the relationship between B and A. Do you mean that B is derived from A?If so, C# 4 will not necessarily make such a thing happen automatically. The types
X<A>
andX<B>
are not compatible at all by default. IfX
is aninterface
and the type parameter is marked asout
, thenX<B>
can be assigned to a variable of typeX<A>
. But note that this is for interfaces only, not concrete types (there is a similar provision for delegates, but that's all).Edit:
So therefore what you want to do is simulate the way that
X<B>
can be assigned to a variable of typeX<A>
in C#/CLR 4.0, where X is an interface.Suppose X is:
You have an
X<B>
, you need anX<A>
. You know thatB
is assignable toA
. So you need the following adaptor:You just forward each method on to the real implementation.
However, you would need such a wrapper class for every possible combination of generic outer classes and pairs of generic parameters related by inheritance. It would be a tedious, error-prone and never-complete task to write them all by hand and maintain a big lookup to pick the right one for a given situation.
So now you're into code generation to manufacture the wrapper classes at runtime.