简体   繁体   中英

How can I cast an Interface as its type in c#?

I have a property that returns an interface. During debugging I can break on what was returned and while it is the interface, Visual Studio is smart enough to know the derived type that it actually is. I assume it's using reflection or something. I'm not sure. My question is, can I have that same info available to me at runtime so I can create a variable of the appropriate type and cast the interface as that? Here is what I am saying:

IPreDisplay preDisplay = cb.PreDisplay;

If preDisplay is a RedPreDisplay I would like to be able to code

RedPreDisplay tmp = preDisplay as RedPreDisplay;

Or if preDisplay were a GreenPreDisplay...

GreenPreDisplay tmp = preDisplay as GreenPreDisplay;

etc... I would like to avoid a messy switch statement if possible, and If I could use generics that would be great.

If you have any advice or examples of how I can do this, please share.

When you hit a situation where you need to do this, it means you're doing something wrong. You need to back up and figure out why your design demands that you do this. If you find yourself stuck there, I strongly recommend you post a new question to get help with the design - there are a lot of smart people here who can help.

To answer your question directly, no - you cannot do this without some kind of if/else or conditional, because you have to be explicit with static types. You could use reflection to call the method, but since you seem to need to call something the interface does not support - but some objects do - you would need to code a per-static-type condition anyway to call that method. Just code the types directly.

Edit: per the discussion in the comments, the best solution to this is to add a second interface to the classes which have this other property or method. Then you can do a simple check:

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

The entire purpose of using interfaces is that the executing code does not have to be aware of the exact type . Try to expose all the information you might need via the interface itself, so you have no need to cast.

Understandably, you may still need to cast an interface to a concrete implementation (specific type) on a rare occasion. If you could provide a bit more context, that might be helpful.

Depending on what it is you're trying to do, you should probably add an action method/ property to the interface, that way you don't need to know the type - which is polymorphism.

Eg:

 IResultLiteEntity preDisplay = cb.PreDisplay;
 preDisplay.Render (); // New Render method on the interface...

@Rex M is absolutely correct. The problem lies with your code and the underlying structure. As a rule, you should not do what you are trying to do; code against the interface only .

That said, there is the is operator that might help you if you've inherited bad code and need to monkey-patch it. For example:

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

Generics will not help you, nor will you be able to do this as part of a switch statement. But it'll get you something working, albeit working in a very ugly way.

As other responders have pointed out, you probably should consider why your design requires different logic for different types that can't be pulled up into an interface.

However, assuming that there are good reasons for this, you only have a few options:

  1. Use reflection. This is generally slow and error prone code, that's also fragile when your implementation changes (ie methods are renamed, etc).
  2. Use an if/else if/else pattern to dispatch based on runtime checks of the type. This is pretty much your only other choice in pre-4.0 versions of C#.
  3. If you are using C# 4.0, you can use assign the object to a dynamic var , and at runtime dispatch to an overloaded method whose signature varies for each of the types supported (see example below).

Here's a C# 4.0 dynamic dispatch example:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM