通用类可以产生相同的签名重载吗?

时间:2012-10-23 14:26:06

标签: c#

  

可能重复:
  Generic methods and method overloading

好的,我偶然碰到了这个......给出了这种情况:

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,我可以区分调用,所以问题是:

  1. 为什么C#不会吓坏?安德斯·海尔斯伯格不应该感受到这种力量的干扰吗?

  2. 如何限制某些类型的泛型参数?因为在这个T中可以是任何东西而不是整数(但很长都可以)

4 个答案:

答案 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)

作为Eric Lippert says

  

C#规范说当你在调用ReallyDoIt(string)和ReallyDoIt(string)之间做出选择 - 也就是说,   当选择在两个具有相同签名的方法之间时,   但是一个人通过泛型替换获得了这个签名 - 然后我们选择   “替代”签名上的“自然”签名。

此过程也在C#规范7.5.3.2(更好的功能成员)中描述:

如果参数类型序列{P1,P2,...,PN}和{Q1,Q2,...,QN}是等效的(即每个Pi具有到相应Qi的标识转换),则以下打破平局规则按顺序应用,以确定更好的功能成员。

  • 如果MP是非泛型方法而MQ是泛型方法,那么MP优于MQ(正如John指出的那样,当你使用泛型方法时,这是正确的,而不是泛型类型)
  • ...
  • 否则,如果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”是表格。当然,使用索引访问器作为对象而不是数字......好吧,无论如何,它都有效。

但是像其他人说的那样,编译器会更喜欢显式而非隐式。