在c#中将引用转换为泛型类

本文关键字:转换 泛型类 引用 | 更新日期: 2023-09-27 18:04:55

我首先在更复杂的上下文中尝试了通用类转换,结果发现这是不可能的。为了演示,我写了这个例子,它是我能想到的问题的最一般的表述,省略了任何不必要的东西:

using System;
using System.Collections.Generic;
namespace testapp
{
    class Program
    {
        static void Main(string[] args)
        {
            // problem
            Generic<Sub> subvar = new Generic<Sub>();
            Generic<Super> supervar;
            supervar = (Generic<Super>)subvar; // <--fails
            // reason for asking
            List<Generic<Super>> list = new List<Generic<Super>>();
            list.Add(supervar);
        }
    }
    class Super { }
    class Sub:Super { }
    class Generic<T> where T : Super { }
}

所以一般来说:因为每个"Sub"都是"Super",所以我认为每个"Sub的泛型"都是"Super的泛型"。因此,我期望将对Generic<Sub>的引用赋值给Generic<Super>的变量是没有问题的,即使没有显式的类型转换。

但是。net框架告诉我这个转换是被禁止的,为什么?

那么,我为什么要这样做呢?假设我想构建一个只接受"任何泛型"的集合,我该如何规避转换呢?

在c#中将引用转换为泛型类

如下所述:https://msdn.microsoft.com/en-us/library/dd469487.aspx您可以使用out通用修饰符来实现您的目标。

对于这个,你必须添加一个新的接口,看起来像这样:
interface IGeneric<out T> where T: Super{}

然后将泛型Class更改为:

class Generic<T> : IGeneric<T> where T : Super

那么你的Main就是:

static void Main(string[] args)
{
    IGeneric<Sub> subvar = new Generic<Sub>();
    IGeneric<Super> supervar;
    supervar = subvar; // No cast required
    List<IGeneric<Super>> list = new List<IGeneric<Super>>();
    ist.Add(supervar);
}

你已经跌入了一个奇妙的通用变异世界。泛型类总是类型不变的;换句话说,除非T1T2是完全相同的类型,否则C<T1>不能转换为C<T2>

接口可以分别与inout声明为逆变和协变。这允许分别"向上"answers"向下"强制转换,但类不能。

参见https://stackoverflow.com/a/2720046/7122,可以很好地解释方差和为什么List是不变的。