是否有值类型的解决方法使得通用推理变得不可能?

时间:2015-07-09 22:36:10

标签: c# generics type-inference value-type

使用如下定义的方法:

public class Foo<T1>
{
    public void Bar<T2>(IQux<IBaz<T1, T2>> baz) { }
}

public interface IBaz<T1, T2> { }

public struct Baz : IBaz<SomeType, AnotherType> { }

public interface IQux<out T> {}

public class Qux<T> : IQux<T> {}

在调用它时,显然不可能Bar推断T2AnotherType

new Foo<SomeType>().Bar(new Qux<Baz>());

如果 Baz不是结构,这将起作用。当我可以按值保留传递Baz但是能够在这种情况下推断类型时,是否有任何解决方法?

2 个答案:

答案 0 :(得分:3)

这不是通用类型推断问题,而是通用方差问题。 Bar无法将T2推断为AnotherType,因为这无效。

new Foo<SomeType>().Bar<AnotherType>(new Qux<Baz>());

此调用无效,因为Qux<Baz>未实现IQux<IBaz<SomeType,AnotherType>>接口,因为Bar方法需要。 IQux<Baz>无法投放到IQux<IBaz<SomeType,AnotherType>>,因为值类型不支持通用差异。

要使呼叫有效,您需要向Bar方法添加其他通用参数:

public class Foo<T1> {
    public void Bar<T2,TBaz>(IQux<TBaz> baz) where TBaz:IBaz<T1,T2> { }
}

虽然只会使此调用有效:

new Foo<SomeType>().Bar<AnotherType,Baz>(new Qux<Baz>());

这里不能进行泛型类推理。

答案 1 :(得分:1)

我同意PetSerAl's answer中的分析。这不是因为类型推断无法检测到有问题的类型,而是因为您想要推断推断的问题类型对于调用实际上是无效的。类型推断合法地无法识别要在方法的类型参数位置使用的有效类型。

就解决方法而言,在我看来,特别是因为您似乎想要利用IBaz<out T>中的协变类型参数,使Baz成为class一个不错的选择。

作为struct,类型应该是不可变的。因此,将其变为不可变的class将保留值类型语义的许多好处(一个值得注意的例外是容易的数组初始化)。并且它将允许调用成功,即使您明确提供类型参数(如上所述和PerSetAl的答案),在您的代码示例中也不会出现这种情况。