c#为什么可以';t打开的泛型类型不能作为参数传递

本文关键字:泛型类型 不能 参数传递 为什么 | 更新日期: 2023-09-27 18:28:30

为什么不能将打开的泛型类型作为参数传递。我经常上这样的课:

public class Example<T> where T: BaseClass
{
   public int a {get; set;}
   public List<T> mylist {get; set;}
}

假设BaseClass如下所示;

public BaseClass
{
    public int num;
}

然后我想要一种方法说:

public int MyArbitarySumMethod(Example example)//This won't compile Example not closed
{
   int sum = 0;
   foreach(BaseClass i in example.myList)//myList being infered as an IEnumerable
       sum += i.num;
   sum = sum * example.a;
   return sum;
}

然后,我必须编写一个接口,将这一类作为参数传递如下:

public interface IExample
{
public int a {get; set;}
public IEnumerable<BaseClass> myIEnum {get;}
}

然后必须将泛型类修改为:

public class Example<T>: IExample where T: BaseClass
{
   public int a {get; set;}
   public List<T> mylist {get; set;}
   public IEnumerable<BaseClass> myIEnum {get {return myList;} }
}

对于我认为编译器可以推断出的内容,这是一个很大的仪式。即使有些事情无法改变,如果我知道语法捷径缺失的原因/理由,我会发现这在心理上非常有帮助。

c#为什么可以';t打开的泛型类型不能作为参数传递

我也遇到过类似的情况,但我从未遇到过这个(非常好!)问题。现在我不得不考虑一下,以下是我的答案:

您期望以下内容起作用:

void F(Example<> e) {
   Console.WriteLine(e.a); //could work
}

是的,这理论上可行,但不行:

void F(Example<> e) {
   Console.WriteLine(e.mylist); //?? type unknown
}

您希望编译器和CLR能够分析方法体,并证明在第一种情况下确实不可能进行不安全的访问。可以工作。为什么没有?也许,这个设计并不是很合理和令人困惑。此外,"默认情况下,所有功能都没有实现。必须有人来实现、测试和记录它们。"

编辑:我想指出的是,如果没有CLR的合作,这个功能是无法实现的。C#编译器必须发出要调用的确切方法,这在开放泛型类型上是不可能的。类型系统现在甚至不允许使用这样的变量。

一个实现原理是:支持这一点需要所有非私有泛型类方法都是虚拟的,否则就无法知道为"open"泛型类型调用哪个特定方法。不同的闭类型方法有不同的jitting,具有不同的对应方法指针。手动定义接口对应于指示编译器哪些方法必须被视为虚拟方法,还允许您指定要公开的"打开"功能的确切子集。您的建议基本上是,所有泛型类都有一个为其公共接口的"开放"部分隐式生成的接口类,即使从未使用过此功能,这也会对类的性能产生影响。

也许我不理解你的确切问题,但你可以通过如下声明让你的"MyArbitrarySumMethod"取一个任意的例子:

public int MyArbitarySumMethod<T>(Example<T> example) where T : BaseClass

然后,您可以在不指定"T"的情况下调用它:

int sum = MyArbitrarySumMethod(myExampleInstance);

这就是你要找的吗?