4

可能重复:
泛型方法和方法重载

好的,我不小心撞到了这个……鉴于这种情况:

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 作为泛型类型参数,我可以区分调用,所以问题是:

  1. 为什么 C# 不惊慌失措?Anders Hejlsberg 不应该感到原力受到干扰吗?

  2. 如何限制某些类型的泛型参数?因为在这个 T 可以是除整数之外的任何东西(但 long 是可以的)

4

4 回答 4

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 可以是除整数之外的任何东西(但 long 是可以的)

这确实是一个完全独立的问题,但基本上你不能。您可以通过各种方式约束类型参数,但不能通过显式包含和排除类型。有关更多信息,请参阅有关约束的 MSDN 页面

于 2012-10-23T14:31:11.297 回答
8

正如Eric Lippert 所说

The C# specification says that when you have a choice between calling ReallyDoIt(string) and ReallyDoIt(string) – that is, when the choice is between two methods that have identical signatures, but one gets that signature via generic substitution – then we pick the “自然”签名优于“替代”签名。

此过程也在 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 更具体:

    • 类型参数不如非类型参数特定(这是您的情况 - 因此方法不是通用的,并且推断的参数类型等于非通用参数类型)
于 2012-10-23T14:30:55.230 回答
0

如果调用可以同时适合这两个 =),C# 编译器总是选择更具体而不是更通用的方法。这就是为什么它不会惊慌失措,他只是遵守他的规则。

于 2012-10-23T14:33:25.460 回答
-2

C# 编译器不会崩溃,因为这两种方法都是有效的,并且都可以调用。

这是一个返回“2”的示例:

Gen<Form> gen = new Gen<Form>();
textBox1.Text = gen[this].ToString();

其中“this”是一种形式。当然,使用索引访问器作为对象而不是数字......好吧,无论如何,它可以工作。

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

于 2012-10-23T14:36:23.353 回答