c# - 如何对值类型使用协方差?

标签 c# covariance

您不能对值类型使用协方差:

Func<string> refTypeFunc = () => "foo";
Func<int> valueTypeFunc = () => 123;

Func<object> a = refTypeFunc; // works
Func<object> b = valueTypeFunc; // doesn't work

This answer by Jon Skeet解释原因:

Basically, variance applies when the CLR can ensure that it doesn't need to make any representational change to the values. References all look the same - so you can use an IEnumerable<string> as an IEnumerable<object> without any change in representation; the native code itself doesn't need to know what you're doing with the values at all, so long as the infrastructure has guaranteed that it will definitely be valid.

For value types, that doesn't work - to treat an IEnumerable<int> as an IEnumerable<object>, the code using the sequence would have to know whether to perform a boxing conversion or not.

好吧,便便。至少对于Func你可以这样做:

Func<object> c = () => valueTypeFunc();

但是,这种简单的方法在大多数情况下并不适用。假设我有一个接口(interface)定义为:

interface ICovariant<out T>
{
    Func<T> InnerFunc { get; }
}

现在如果我有 ICovariant<T> ,我无法将其转换到 ICovariant<object> ,而且我认为没有简单的方法可以解决这个问题。我知道T可以是object - 一切都可以。这种情况我能做什么?如果没有简单的解决方法,那么还有什么是最好的方法?

最佳答案

您必须对协变接口(interface)进行特殊实现才能为您完成该转换。像这样的事情:

public class Boxer<T, U> : ICovariant<T> where U : struct, T
{
    public Boxer( ICovariant<U> foo )
    {
        mFoo = foo;
    }

    public Func<T> CallMe => () => mFoo.CallMe();

    private readonly ICovariant<U> mFoo;
}

现在允许您包装 ICovariant<T> 的值类型实现界面。如果您发现所有泛型参数都难以输入,您可以创建一个静态方法来为您进行推导:

static void BoxIt<T, U>( IFoo<U> fooU, out IFoo<T> fooT ) where U : struct, T
{
    fooT = new Boxer<T, U>( fooU );
}

关于c# - 如何对值类型使用协方差?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36364062/

相关文章:

c# - 以 "1"结尾的变量在 ILSpy 中删除了 "1"。为什么?

ocaml - OCaml方差(+'a,-'a)和不变性

visual-c++ - 如何在 IplImage 上使用 calcCovarMatrix?

r - lme4计算协方差的置信区间

scala - 为什么方法和类型对方差施加不同的约束?

c# - 在 C# 中创建不透明指针(引用)

c# - 如何在 ASP.NET Core MVC 中完成这个 nl 到 br 的功能?

c# - 有两个不同的依赖程序集但具有相同的公钥 token 是否正常?

c# - 如何在 C# 泛型中将子类转换为父类

C# 图表适合一个选项卡