【问题标题】:Cast T as having an interface?将 T 转换为具有接口?
【发布时间】:2024-01-19 11:04:01
【问题描述】:

假设我有一个方法:

public void DoStuff<T>() where T : IMyInterface {
 ...
}

在其他地方我想调用不同的方法

public void OtherMethod<T>() where T : class {
...
if (typeof(T) is IMyInterface) // have ascertained that T is IMyInterface
   DoStuff<T>();
}

有什么方法可以将 T 转换为具有我的界面吗?

DoStuff&lt;(IMyInterface)T&gt; 和其他类似的变体对我不起作用。

编辑:感谢您指出typeof(T) is IMyInterface 是检查接口的错误方法,应该在实际的 T 实例上调用。

Edit2:我发现(IMyInterface).IsAssignableFrom(typeof(T)) 可以检查接口。

【问题讨论】:

  • 你就不能叫它DuStuff&lt;IMyInterface&gt;吗?
  • 还有一个想法:我认为如果你在泛型方法中需要typeof(T),也许你根本不应该使用泛型?
  • @MarcinJuraszek 我不同意。有时您可能希望在通用方法中使用typeof(T)。事实上,我敢打赌,泛型是typeof 语句最常见的用法。
  • typeof(T) is IMyInterface 始终为假。但我想你的意思是theinstanceOfT is IMyInterface,对吧?
  • 是的,我想是的,Mikael。谢谢

标签: c# generics interface casting


【解决方案1】:

您的示例需要做一些工作。你在这里做什么很大程度上取决于你如何在DoStuff&lt;T&gt; 方法中使用IMyInterface

您的DoStuff 方法真的需要T 吗?还是只需要IMyInterface?在我的示例中,我将一个对象传递给OtherMethod,确定它是否实现IMyInterface,调用DoStuff,并调用该对象的接口方法。

你在传递物体吗?您如何在OtherMethodDoStuff 中使用TIMyInterface 类型?

如果您的 DoStuff 方法需要同时了解类型 T 和接口 IMyInterface,则它应该只需要通用 T : IMyInterface

public void DoStuff(IMyInterface myObject)
{
    myObject.InterfaceMethod();
}

public void OtherMethod<T>(T myObject)
    where T : class
{
    if (myObject is IMyInterface) // have ascertained that T is IMyInterface
    {
        DoStuff((IMyInterface)myObject);
    }
}

【讨论】:

    【解决方案2】:

    这一行是错误的:

    if (typeof(T) is IMyInterface) // have ascertained that T is IMyInterface
       DoStuff<T>();
    

    typeof(T) 返回一个Type,它永远不会IMyinterface。如果你有一个 T 的实例,你可以使用

    if (instanceOfT is IMyInterface) // have ascertained that T is IMyInterface
       DoStuff<T>();
    

    if (instanceOfT is IMyInterface) // have ascertained that T is IMyInterface
       DoStuff<IMyInterface>();
    

    否则你可以使用反射作为Tim S suggests

    【讨论】:

      【解决方案3】:

      您可以使用相同的语法从多个接口继承:

      public void OtherMethod<T>() where T : class, IMyInterface {
      ...
      }
      

      【讨论】:

      • 这可能不是一个选项(IMyInterface 可能是可选的),但如果你能做到,这将是我的首选方法。
      • 谢谢,是的,我也试过了。问题是它会冒泡到调用方法。所以从 OtherMethod 传递的 T 也必须是 T : class, IMyInterface 并且在我的代码中并非总是如此
      【解决方案4】:

      我认为最直接的方法是反思。例如

      public void OtherMethod<T>() where T : class {
          if (typeof(IMyInterface).IsAssignableFrom(typeof(T))) {
              MethodInfo method = this.GetType().GetMethod("DoStuff");
              MethodInfo generic = method.MakeGenericMethod(typeof(T));
              generic.Invoke(this, null);
          }
      }
      

      【讨论】:

      • 是的,我希望我可以避免这种情况,因为我已经在各处创建通用方法了!谢谢,不过
      • @DevDave 是的,IMO 它显示了 C# 的泛型支持的缺点,即没有更好的方法可以做到这一点。您不能事后添加约束,不能有两个具有相同参数但类型约束不同的方法,或者任何其他使这变得容易的方法。