7
interface IBar { void Hidden(); }

class Foo : IBar { public void Visible() { /*...*/ } void IBar.Hidden() { /*...*/ } }

class Program
{
    static T CallHidden1<T>(T foo) where T : Foo
    {
        foo.Visible();
        ((IBar)foo).Hidden();   //Cast required

        return foo;
    }

    static T CallHidden2<T>(T foo) where T : Foo, IBar
    {
        foo.Visible();
        foo.Hidden();   //OK

        return foo;
    }
}

实际编译的代码有什么区别(CallHidden1 与 CallHidden2)吗?在访问显式实现的接口成员时, where T : Foo 和 where T : Foo, IBar (如果 Foo 实现 IBar)之间还有其他区别吗?

4

2 回答 2

6

生成的 IL 略有不同:

    L_000d: ldarg.0 
    L_000e: box !!T
    L_0013: callvirt instance void WindowsFormsApplication1.IBar::Hidden()

对比

    L_000d: ldarga.s foo
    L_000f: constrained !!T
    L_0015: callvirt instance void WindowsFormsApplication1.IBar::Hidden()

如果T是一个值类型,这将导致foo被装箱CallHidden1但不在CallHidden2. 但是,由于Foo是类,因此任何T派生自的类型Foo都不是值类型,因此行为将是相同的。

于 2010-02-05T16:55:04.960 回答
1

是的,一点点,因为第二个指定必须实现接口,如果Foo稍后更改它可能会变得很重要以使其不实现IBar实现,这可能会变得很重要。

这将使其不适合CallHidden2<>在编译时保持有效的情况下使用(如果不再由 实现,CallHidden1<>则在运行时将失败)。IBarFoo

因此,如果它们位于单独的程序集中,则不同的元数据会有所不同。然而,执行的 IL 将非常相似,如果不相同的话。

于 2010-02-05T16:34:27.850 回答