c#为什么可以';是否打开泛型类型作为参数传递?

c#为什么可以';是否打开泛型类型作为参数传递?,c#,generics,C#,Generics,为什么不能打开泛型类型作为参数传递。我经常上这样的课: public class Example<T> where T: BaseClass { public int a {get; set;} public List<T> mylist {get; set;} } 然后我想要一种方法,比如: public int MyArbitarySumMethod(Example example)//This won't compile Example not clo

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

public class Example<T> where T: BaseClass
{
   public int a {get; set;}
   public List<T> mylist {get; set;}
}
然后我想要一种方法,比如:

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;}
}
公共接口示例
{
公共int a{get;set;}
公共IEnumerable 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;} }
}
public类示例:IExample其中T:BaseClass
{
公共int a{get;set;}
公共列表mylist{get;set;}
公共IEnumerable myIEnum{get{return myList;}}
}

对于我认为编译器可以推断的东西,这是一个非常隆重的仪式。即使某些东西无法改变,如果我知道没有语法捷径的原因/理由,我发现这在心理上非常有用。

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

您希望以下各项起作用:

void F(Example<> e) {
   Console.WriteLine(e.a); //could work
}
void F(示例e){
Console.WriteLine(e.a);//可以工作
}
是的,这在理论上是可行的,但这不会:

void F(Example<> e) {
   Console.WriteLine(e.mylist); //?? type unknown
}
void F(示例e){
Console.WriteLine(e.mylist);//?类型未知
}
您希望编译器和CLR能够分析方法体,并证明在第一种情况下不可能进行不安全的访问。这是可以实现的。为什么不是呢?也许,这个设计并不十分合理和令人困惑。此外,“默认情况下,所有功能都未实现。必须有人实现、测试和记录它们。”


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

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

也许我不理解您的确切问题,但您可以使用“MyArricrySumMethod”举一个任意的例子,如下所示:

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

这就是你想要的吗?

你所说的限制不是很清楚,因为你还没有展示你是如何试图通过限制的。我想我知道你的意思,但问题不清楚……你问“[如何]打开泛型类型”是什么意思?@Rich,如果
t
仍然未指明,你将如何在语法上传递
Example
(即使在原则上也是如此?@JonSkeet,@Kirk Woll,希望编辑已经澄清了这一点。您可以将
MyArbitarySumMethod
修改为
MyArbitarySumMethod(示例),其中T:BaseClass
。然而,调用者仍然需要知道类型。事实上,默认情况下,所有功能都没有实现,但我经常使用泛型,我反复发现自己反复输入相同的模式。我感到惊讶的是,其他人没有强烈感觉到对这个功能的需求。关闭类型本质上是一种继承形式。我的经验告诉我,这种情况有时会发生,但很少发生。当然,这完全取决于项目。但我的主要观点是,这个特性可能会让人困惑(“为什么我可以访问一个而不是mylist?”“为什么这个可行而不是那个?”),而且要找到一个完全适用于所有情况的好解决方案可能并不容易。也许我没有编写典型的C代码。我必须承认,在夜深人静的时候,Smalltalk和Lisp的想法掠过我的脑海。@Rich,就我自己而言,我个人非常高兴C#避开了这个特性——不这样做的后果可以从Java的通配符匹配实现中看出(
MyClass@RichOliver,我百分之百同意你的看法。我一次又一次地遇到这种情况,我想知道为什么这对CLR和c#的设计者来说并不微不足道。在我当前的项目中,我大量使用泛型,而这个小功能的存在可能会抹去我的大部分
类型(…).GetMethod(…).MakeGenricMethod(…).Invoke(…)正如……
在我的代码中发生过无数次一样。@KirkWoll:不,我不这么认为。这种方法正是我要建议的方法。@Jon,我想你是对的。在我看来,OP是在寻找一种通用的方法来传递泛型类型,而不必引用
t
——一般的解决方案是编写一个接口包装器。但是对于一个方法的特定用例,你是对的,这会起作用。事实上,情况比这更糟。如果一个
Foo
有一个类型为
int
Foo.Bar
Foo.Bar
Foo.Bar
Foo.Bar
,等等的静态字段
Bar
,都会引用它到可能具有不同值的不同存储位置。
Foo.Bar
将引用到哪个存储位置?由于编译器调用某些
Foo
上的某个成员无法判断该成员是否可以直接或间接访问
Foo.Bar
,因此无法知道r任何不带参数调用
Foo
的尝试都可能是安全的。
public int MyArbitarySumMethod<T>(Example<T> example) where T : BaseClass
int sum = MyArbitrarySumMethod(myExampleInstance);