如何将接口转换为c#中的类型?

如何将接口转换为c#中的类型?,c#,.net,interface,casting,polymorphism,C#,.net,Interface,Casting,Polymorphism,我有一个返回接口的属性。在调试期间,我可以中断返回的内容,虽然它是接口,但VisualStudio足够聪明,可以知道它实际上是什么派生类型。我想它是在使用反射或其他东西。我不确定。我的问题是,我是否可以在运行时获得相同的信息,以便创建适当类型的变量并按此方式转换接口?我的意思是: IPreDisplay preDisplay = cb.PreDisplay; 如果preDisplay是一个RedPreDisplay,我希望能够编写代码 RedPreDisplay tmp = preDispla

我有一个返回接口的属性。在调试期间,我可以中断返回的内容,虽然它是接口,但VisualStudio足够聪明,可以知道它实际上是什么派生类型。我想它是在使用反射或其他东西。我不确定。我的问题是,我是否可以在运行时获得相同的信息,以便创建适当类型的变量并按此方式转换接口?我的意思是:

IPreDisplay preDisplay = cb.PreDisplay;
如果preDisplay是一个RedPreDisplay,我希望能够编写代码

RedPreDisplay tmp = preDisplay as RedPreDisplay;
或者如果preDisplay是绿色preDisplay

GreenPreDisplay tmp = preDisplay as GreenPreDisplay;
等等。。。 如果可能的话,我希望避免一个混乱的switch语句,如果我可以使用泛型,那就太好了


如果您有任何建议或示例,请与我分享。

根据您尝试执行的操作,您可能应该向接口添加操作方法/属性,这样您就不需要知道类型-即多态性

例如:


当你遇到需要这样做的情况时,这意味着你做错了什么。您需要备份并找出设计要求您这样做的原因。如果你发现自己被困在那里,我强烈建议你发布一个新的问题来获得设计方面的帮助——这里有很多聪明的人可以提供帮助

要直接回答您的问题,不-您不能在没有某种if/else或条件的情况下这样做,因为您必须显式使用静态类型。您可以使用反射来调用该方法,但由于您似乎需要调用接口不支持的东西(但某些对象支持),因此无论如何,您都需要编写每个静态类型的条件来调用该方法。直接对类型进行编码即可

编辑:根据评论中的讨论,最好的解决方案是为具有此其他属性或方法的类添加第二个接口。然后你可以做一个简单的检查:

IPreDisplay display = cb.PreDisplay;
IOtherInterface displayAsOther = display as IOtherInterface;
if(displayAsOther != null)
{
    displayAsOther.OtherMethod();
}

使用接口的全部目的是执行代码不必知道确切的类型。尝试通过接口本身公开所有可能需要的信息,这样就不需要强制转换


可以理解,在极少数情况下,您可能仍然需要将接口转换为具体实现(特定类型)。如果您能提供更多的上下文,这可能会有所帮助。

@Rex M绝对正确。问题在于代码和底层结构。一般来说,你不应该做你想做的事;仅针对接口编写代码

也就是说,如果您继承了坏代码并需要对其进行修补,那么
is
操作符可能会对您有所帮助。例如:

if(myInstance is MyBaseType)
{
  MyBaseType myInstanceAsBaseType = myInstance as MyBaseType;
  // handle MyBaseType specific issue
}
else if(myInstance is MyOtherBaseType)
{
  MyOtherBaseType myInstanceAsOtherBaseType = myInstance as MyOtherBaseType;
  // handle MyOtherBaseType specific issue.
}

泛型对您没有帮助,您也不能在switch语句中这样做。但它会让你的工作,虽然工作方式非常丑陋
  • 使用反射。这通常是缓慢且容易出错的代码,当您的实现发生更改(即方法重命名等)时,这也是脆弱的
  • 使用if/else if/else模式根据该类型的运行时检查进行调度。在C#4.0之前的版本中,这几乎是您唯一的选择
  • 如果您使用的是C#4.0,则可以使用将对象分配给动态变量,并在运行时分配给重载方法,该重载方法的签名因支持的每种类型而异(请参见下面的示例)
  • 下面是一个C#4.0动态调度示例:

    void Foo()
    {
      dynamic preDisplay = cb.PreDisplay;
      DoSomethingWith( preDisplay );  // runtime dispatch using dynamic runtime (DLR)
    }
    
    void DoSomethingWith( RedPreDisplay r ) { ... }  // code specific to RefPreDisplay
    void DoSomethingWith( GreenPreDisplay g ) { ... } // code specific to GreenPreDisplay
    void DoSomethingWIth( IPreDisplay o ) { ... }  // catch-all
    

    你为什么要这么做?当您将接口转换为适当的类型时,当您想要使用它时,返回接口的目的难道不是丢失了吗?您的问题揭示了一些基本的混乱(或者您在语言上过于草率),没有任何东西可以“返回”接口,因为在运行时接口不存在。它将某个具体类型的对象“CAST”返回到接口。但是cast并没有改变对象,它只是改变了持有引用的变量的性质object@Charles布雷塔纳:不幸的是,你觉得有必要说明你刚才做了什么;太多人不理解对象实例和它所针对的类型之间的区别。我建议阅读Liskov替换原则:(所有派生类型都应该能够被视为基本类型):在C#4.0中,如果不使用switch/else,您可以在运行时使用dynamic关键字将类型分派给具有特定签名的方法。@LBushkin非常正确,但C#4.0尚未发布,因此不能合理地假设每个有4可能解决的问题的人都可以简单地切换到beta版本。即使是RTM,即使可以在C#4中实现,也可能不是一个好主意。即使在支持它的语言(如VBScript)中,我也从未使用过它。IPreDisplay在整个应用程序中都使用。一些实现它的对象没有接口不提供的属性。我认为我的最佳选择是创建一个新的接口,并用一小组对象实现它。也许这就是这里的解决办法。@Kettenbach这听起来确实是个好办法。接口的用途范围应尽可能有限,因此,如果您有一些对象实现的新功能子集,则该子集应为单独的接口。
    void Foo()
    {
      dynamic preDisplay = cb.PreDisplay;
      DoSomethingWith( preDisplay );  // runtime dispatch using dynamic runtime (DLR)
    }
    
    void DoSomethingWith( RedPreDisplay r ) { ... }  // code specific to RefPreDisplay
    void DoSomethingWith( GreenPreDisplay g ) { ... } // code specific to GreenPreDisplay
    void DoSomethingWIth( IPreDisplay o ) { ... }  // catch-all