我有两个协变的接口,两个接口都是这样传递的:
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);
}
它的目的是允许可选的“跟踪器”看到事情发生/修改表演者的结果。
答案 0 :(得分:0)
只需将Tracer<in T>
修改为Tracer
(非通用)并定义void Perform(T t, Tracer tracer);
即可。
无论如何,您的代码未在T
中使用Tracer
。
由于您使用新的详细信息编辑了问题,因此替代修复方法是从泛型定义中删除。你不需要它。另一种实现目标的方法是:
public interface Performer<T>
{
bool Perform(T t, Tracer tracer = null);
}
public interface Tracer
{
bool Notify<T>(Performer<T> performer);
}
注意:删除ref bool并返回bool而不是
答案 1 :(得分:0)
根据您提供的内容,我一起避免了这个问题,修改Tracer界面以删除T,因为它不需要:
public interface INotify
{
void Notify();
}
然后只需在表演者中接受新界面
public interface Perfomer<in T>
{
void Perform(T t, INotify entity);
}
PS:您的界面名称中可能有一个类型Perfomer =&gt;表演者
答案 2 :(得分:0)
当您声明Performer
是逆变的时,您声明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();
}