Explicitly implemented interface and generic const

2019-04-06 22:45发布

问题:

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;
    }
}

Is there any difference (CallHidden1 vs. CallHidden2) is actual compiled code? Is there other differences between where T : Foo and where T : Foo, IBar (if Foo implements IBar) that in accessing explicitly implemented interface members ?

回答1:

The IL generated is slightly different:

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

vs.

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

If T were a value type, this would result in foo being boxed in CallHidden1 but not in CallHidden2. However, since Foo is a class, any type T derived from Foo will not be a value type, and thus the behavior will be identical.



回答2:

Yes, a tiny bit, since the second specifies that the interface must be implemented, which may become important if Foo is later changed so that it does not implement IBar.

That would make it unsuitable for being used in CallHidden2<> while remaining valid at compile time for CallHidden1<> (which would then fail at runtime if IBar is no longer being implemented by Foo).

So if they are in separate assemblies, the different metadata would make a difference. The executed IL will, however, be pretty similar if not the same.