我有一个返回接口的属性。在调试期间,我可以打破返回的内容,当它是界面时,Visual Studio足够聪明,可以知道它实际上是派生类型。我假设它使用反射或其他东西。我不确定。我的问题是,我可以在运行时向我提供相同的信息,这样我就可以创建一个适当类型的变量并将接口转换为那样的接口吗?这就是我的意思:
IPreDisplay preDisplay = cb.PreDisplay;
如果preDisplay是RedPreDisplay,我希望能够编码
RedPreDisplay tmp = preDisplay as RedPreDisplay;
或者,如果preDisplay是GreenPreDisplay ......
GreenPreDisplay tmp = preDisplay as GreenPreDisplay;
...等 如果可能的话,我想避免使用混乱的switch语句,如果我可以使用非常棒的泛型。
如果您有任何关于我如何做到的建议或示例,请分享。
答案 0 :(得分:17)
当你遇到需要这样做的情况时,这意味着你做错了什么。您需要备份并找出您的设计要求您执行此操作的原因。如果您发现自己被困在那里,我强烈建议您发布一个新问题以获得设计方面的帮助 - 这里有很多聪明人可以提供帮助。
直接回答你的问题,不 - 如果没有某种if / else或条件,你不能这样做,因为你必须明确静态类型。您可以使用反射来调用该方法,但由于您似乎需要调用接口不支持的东西 - 但是某些对象会这样做 - 您需要编写一个每静态类型的条件来调用该方法。只需直接编码类型。
根据评论中的讨论,编辑,对此的最佳解决方案是向具有此其他属性或方法的类添加第二个接口。然后你可以做一个简单的检查:
IPreDisplay display = cb.PreDisplay;
IOtherInterface displayAsOther = display as IOtherInterface;
if(displayAsOther != null)
{
displayAsOther.OtherMethod();
}
答案 1 :(得分:6)
使用接口的全部目的是执行代码不必知道确切的类型。尝试通过界面本身公开您可能需要的所有信息,因此您无需投射。
可以理解,您可能仍需要在极少数情况下将接口强制转换为具体实现(特定类型)。如果您可以提供更多上下文,那可能会有所帮助。
答案 2 :(得分:4)
根据您尝试做的事情,您可能应该在界面中添加一个操作方法/属性,这样您就不需要知道类型 - 这是多态性。
E.g:
IResultLiteEntity preDisplay = cb.PreDisplay;
preDisplay.Render (); // New Render method on the interface...
答案 3 :(得分:3)
@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语句的一部分。但它会给你一些工作,虽然工作非常丑陋。
答案 4 :(得分:3)
正如其他响应者所指出的那样,您可能应该考虑为什么您的设计需要针对不能被提升到接口的不同类型的不同逻辑。
但是,假设有充分的理由,你只有几个选择:
这是一个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