好的,我偶然碰到了这个......给出了这种情况:
class Program {
static void Main( string[ ] args ) {
var obj = new gen<int>( );
Console.Write( obj[ 1 ] );
Console.ReadKey( );
}
}
class gen<T> {
public int this[ T i ] { get { return 2; } }
public int this[ int i ] { get { return 1; } }
}
它将始终打印1.我希望编译器能够抱怨,或者运行时崩溃并烧毁CPU,但不,它很高兴打印'1'
当然,如果我使用任何其他类型的泛型参数,我可以选择返回。对于咯咯笑,我尝试使用UInt作为泛型类型的parmater,我可以区分调用,所以问题是:
为什么C#不会吓坏?安德斯·海尔斯伯格不应该感受到这种力量的干扰吗?
如何限制某些类型的泛型参数?因为在这个T中可以是任何东西而不是整数(但很长都可以)
答案 0 :(得分:9)
我认为这在C#4规范(更好的功能成员)的第7.5.3.2节中有详细说明。
- 否则,如果M P 具有比M Q更多的特定参数类型,则M P 优于MQ [...]
- 类型参数的特定性低于非类型参数
- [...]
所以在这里,T
参数的成员不如具有int
参数的成员具体。
尝试通过不像这样重载来设计你的方法。当然,对于索引者来说很难,但是你总是可以提供方法(或者也可以作为后备)。
编辑:请注意,如果你有重载的方法,其中两个都是类型参数,编译器将抱怨:
public class Foo<T1, T2>
{
public void Bar(T1 t1) {}
public void Bar(T2 t2) {}
}
...
Foo<int, int> foo = new Foo<int, int>();
foo.Bar(10); // Error
这两种方法都不具体。
如何限制某些类型的泛型参数?因为在这个T中可以是任何东西而不是整数(但很长都可以)
这实际上是一个完全独立的问题,但基本上你不能。您可以通过各种方式约束类型参数,但不能通过显式包含和排除类型来约束类型参数。有关详细信息,请参阅the MSDN page on constraints。
答案 1 :(得分:8)
C#规范说当你在调用ReallyDoIt(string)和ReallyDoIt(string)之间做出选择 - 也就是说, 当选择在两个具有相同签名的方法之间时, 但是一个人通过泛型替换获得了这个签名 - 然后我们选择 “替代”签名上的“自然”签名。
此过程也在C#规范7.5.3.2(更好的功能成员)中描述:
如果参数类型序列{P1,P2,...,PN}和{Q1,Q2,...,QN}是等效的(即每个Pi具有到相应Qi的标识转换),则以下打破平局规则按顺序应用,以确定更好的功能成员。
否则,如果MP具有比MQ更多的特定参数类型,则MP优于MQ。设{R1,R2,...,RN}和{S1,S2,...,SN}表示MP和MQ的未实例化和未展开的参数类型。 MP的参数类型比MQ更具体,如果对于每个参数,RX的特定性不低于SX,并且对于至少一个参数,RX比SX更具体:
答案 2 :(得分:0)
如果调用适合两者,则C#编译器总是选择更具体的方法与更通用的方法。这就是为什么它不会吓到,他只是遵循他的规则。
答案 3 :(得分:-2)
C#编译器并不会因为两种方法都有效而烦恼,而且两者都可以被调用。
这是一个返回“2”的例子:
Gen<Form> gen = new Gen<Form>();
textBox1.Text = gen[this].ToString();
“this”是表格。当然,使用索引访问器作为对象而不是数字......好吧,无论如何,它都有效。
但是像其他人说的那样,编译器会更喜欢显式而非隐式。