.NET协变性

9

我有这段简单的代码:

public interface IReader<out T>
{
    IEnumerable<T> GetData();
}

这个接口应该在T上是协变的,我是这样使用它的:

private static Func<bool> MakeSynchroFunc<T>(IReader<T> reader) where T : IComposite
{
    return () => Synchronize(reader);
}

请注意,T必须实现IComposite接口。同步方法输入一个IReader<IComposite>

注意:T必须实现IComposite接口。同步方法需要以IReader<IComposite>作为输入:

private static bool Synchronize(IReader<IComposite> reader)
{
    // ......
}

编译器告诉我无法将IReader<T>转换为IReader<IComposite>,尽管有对T的限制和IReader的协变性。
这里我做错了什么吗? 编译器应该能够验证约束条件,而协变性应该让我把IReader<T>用作IReader<Icomposite>,不是吗?
谢谢。

3
如果 T 是一个结构体,那么它将违反协变性规则。您需要使用 class 约束来满足编译器,以确保它是一个保持标识不变的转换。请参见:这是C#4中的协变性错误吗? - Ani
是的,那就是问题所在,现在它正常工作了。谢谢。 - dou bret
可能是为什么协变不能与泛型方法一起使用的重复问题。 - nawfal
3个回答

5
您可以通过向 T 添加一个 class 约束来解决您的问题。当涉及到结构体时,协变是不起作用的(IEnumerable<int> 无法转换为 IEnumerable<object>)。由于您没有将 T 约束为类,因此您可以传递一个 IReader<实现了 IComposite 的某些结构体>,这将无法转换。

太酷了,现在它可以工作了!我早就知道协变性在值类型上不起作用,但没意识到这是我问题的原因。添加类约束后,它完美地运行了。谢谢! - dou bret

1

很遗憾,泛型不是协变的。尽管 TIComposite 相关,但 IReader<T>IReader<IComposite> 是完全不相关的类型。

编辑:我不知道为什么这在 .Net 4 和 <out T> 中不起作用。有其他人能回答吗?


1
你确定吗?IReader接口定义中的out修饰符应该告诉编译器该接口是协变的。我正在使用.NET 4。 - dou bret
3
这个答案需要澄清,按照现有的写法相当令人困惑。 - Jeff Yates
我之前不知道接口协变的<out>关键字,现在了解了一下,我也看不出为什么OP的代码不能工作。因为我学到了新东西,所以给这个问题点赞,希望其他人也能回答。 - GazTheDestroyer
谢谢您的努力帮助。但我不明白为什么它还是不能工作。 - dou bret

0
为什么不改变函数定义,既然这才是你真正想要的东西呢:
private static Func<bool> MakeSynchroFunc<T>(IReader<IComposite> reader) where T : IComposite

你可能需要泛型参数 T 用于其他事情,所以我把它留在那里。

因为我需要参数T用于其他事情,这只是一个例子,不是真正的代码。我希望让编译器推断出T的类型,而不是必须明确指定它。 - dou bret

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接