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;} }
}
对于我认为编译器可以推断出的内容,这是一个很大的仪式。即使有些事情无法改变,如果我知道语法捷径缺失的原因/理由,我会发现这在心理上非常有帮助。
我也遇到过类似的情况,但我从未遇到过这个(非常好!)问题。现在我不得不考虑一下,以下是我的答案:
您期望以下内容起作用:
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);
这就是你要找的吗?