我有两个接口都是协变的,它们都像这样相互传递:
public interface Perfomer<in T>
{
void Perform(T t, Tracer<T> tracer);
}
public interface Tracer<in T>
{
void Notify();
}
但是,即使两个接口都标记为协变,并且 T 仅用作输入,我仍然收到错误:
"Invalid variance: The type parameter 'T' must be covariantly valid on
'Perfomer<T>.Do(T, Tracer<T>)'. 'T' is contravariant. [_Console].
任何想法为什么使用相同类型的协变接口参数会使 T 逆变?
编辑(对不起,我是 StackOverflow 的新手,根据答案,我意识到我应该在我的问题中更准确,我只是试图消除尽可能多的噪音到单个错误(。
该代码实际上有两个接口,接口大致相似:
public interface Performer<in T>
{
bool Perform(T t, Tracer<T> tracer = null);
}
public interface Tracer<in T>
{
void Notify(Performer<T> performer, T t, ref bool success);
}
其目的是允许可选的"跟踪器"看到事情发生/修改执行者的结果。
当您声明Performer
是逆变时,您是在声明执行者对 T 所做的任何事情也可以对更具体的 T 版本执行。例如,可以赋予作用于对象的操作一个字符串,它就像该字符串是一个对象一样。
例如,您可以这样做,因为所有流都支持Length
:
class MyClass : Performer<Stream>
{
void Perform(Stream t)
{
Console.WriteLine(t.Length)
}
}
Performer<FileStream> p = new MyClass();
p.Perform(new FileStream());
但是你不能这样做,因为你给它提供了一个不支持IsAsync
的类:
class MyClass : Performer<FileStream>
{
void Perform(Stream t)
{
Console.WriteLine(t.IsAsync)
}
}
Performer<Stream> p = new MyClass();
p.Perform(new Stream()); //Stream isn't good enough; it has to be a FileStream, since it needs IsAsync
目前为止,一切都好。现在让我们添加第二个参数:
class MyClass : Performer<Stream>
{
void Perform(Stream t, Tracer<Stream> tracer)
{
Console.WriteLine(tracer.Notify())
}
}
为了使这一点起作用,逆变必须起作用。如果逆变有效,则意味着Perform
可以将Tracer<FileStream>
(您传入(存储在类型为Tracer<Stream>
的变量中(这就是它的实现方式(。这意味着 Tracer 在其类型参数方面必须是协变的。
因此,您可以通过将in
更改为out
来修复代码,如下所示:
public interface Performer<in T>
{
void Perform(T t, Tracer<T> tracer);
}
public interface Tracer<out T> //out instead of in
{
void Notify();
}
从您提供的内容来看,我会一起避免这个问题,修改跟踪器接口以删除 T,因为它不需要:
public interface INotify
{
void Notify();
}
然后只需在您的表演者中引入新界面
public interface Perfomer<in T>
{
void Perform(T t, INotify entity);
}
PS:您的界面名称中可能有一个类型 表演者 => 表演者
只需将Tracer<in T>
修改为Tracer
(非泛型(并定义void Perform(T t, Tracer tracer);
即可。 无论如何,您的代码都没有在Tracer
中使用T
。
由于您使用新的详细信息编辑了问题,因此替代解决方法是从泛型定义中删除。你不需要它。实现所需目标的另一种方法是:
public interface Performer<T>
{
bool Perform(T t, Tracer tracer = null);
}
public interface Tracer
{
bool Notify<T>(Performer<T> performer);
}
注意:删除引用布尔值并返回布尔值