方法参数:接口VS通用类型

Ask*_*ein 6 c# generics

使用这两个方法实现中的一个或另一个的参数是什么(在Example类中)?

public interface IInterface
{
    void DoIt();
}

public class Example
{
    public void MethodInterface(IInterface arg)
    {
        arg.DoIt();
    }

    public void MethodGeneric<T>(T arg) where T: IInterface
    {
        arg.DoIt();
    }
}
Run Code Online (Sandbox Code Playgroud)

PS:如果方法返回一个IInterfaceT,我会选择"通用"方法,以避免在需要时在T类型中进一步转换.

Sri*_*vel 4

两者看似相同,但实际上并非如此。

通用版本在传递时不会装箱,ValueType因为非通用版本需要“装箱”

这是一个小示例程序和相关的 IL,它演示了这种情况

void Main()
{
    Example ex = new Example();
    TestStruct tex = new TestStruct();
    ex.MethodGeneric(tex);
    ex.MethodInterface(tex);
}
public interface IInterface
{
   void DoIt();
}

public class Example
{
   public void MethodInterface(IInterface arg)
   {
       arg.DoIt();
   }

   public void MethodGeneric<T>(T arg) where T : IInterface
   {
       arg.DoIt();
   }
}

internal struct TestStruct : IInterface
{
   public void DoIt()
   {

   }
}
Run Code Online (Sandbox Code Playgroud)

下面是生成的IL的相关部分

IL_0001:  newobj      UserQuery+Example..ctor
IL_0006:  stloc.0     // ex
IL_0007:  ldloca.s    01 // tex
IL_0009:  initobj     UserQuery.TestStruct
IL_000F:  ldloc.0     // ex
IL_0010:  ldloc.1     // tex
IL_0011:  callvirt    UserQuery+Example.MethodGeneric
IL_0016:  nop         
IL_0017:  ldloc.0     // ex
IL_0018:  ldloc.1     // tex
IL_0019:  box         UserQuery.TestStruct //<--Box opcode
IL_001E:  callvirt    UserQuery+Example.MethodInterface
Run Code Online (Sandbox Code Playgroud)

虽然这是一个偏好问题,但MethodGeneric在“ValueTypes”的情况下,While 会表现得更好