fepiv
fepiv

Reputation: 1290

Casting an interface to another interface that it does not inherit

I'm hoping someone here can explain what incorrect assumptions I'm making. In C# 4.0, I have 2 interfaces and a class that implements them both. In a method I declare a variable with the type of the first interface, instantiate it using the class that implements both interfaces and can somehow cast it successfully to the second interface like in the following code:

    public interface IFirstInterface 
    {
        void Method1();
    }

    public interface ISecondInterface
    {
        void Method2();
    }

    public class InterfaceImplementation : IFirstInterface, ISecondInterface
    {
        public void Method1() { }
        public void Method2() { }
    }

    public class SomeClass
    {
        public void SomeMethod()
        {
            IFirstInterface first = new InterfaceImplementation();
            first.Method1();

            // Shouldn't the next line return null?
            ISecondInterface second = first as ISecondInterface; 
            // second is not null and the call to Method2() works fine
            second.Method2();
        }
    }

I'm trying to understand why the casting is successful. Yes, the class implements both interfaces, but I would think that since the first variable is declared as IFirstInterface (which doesn't inherit from ISecondInterface), the casting should still fail.

I've also tried restructuring my code in other ways, such as not using 'as', but the cast is still successful.

What am I missing?

Upvotes: 13

Views: 15912

Answers (6)

fred
fred

Reputation: 1

This really indicates a design flaw. The client sort of knows that both interfaces are implemented by the same object. For you example that's fine but if those interfaces were implemented separately, you wouldn't be able to jump form the first to the second one. Ideally it would be better to have some kind of query interface where you could go from one type to the other.

Upvotes: 0

DRapp
DRapp

Reputation: 48139

From your example, you should be good by testing type type before calling any of the functionality. The first creation will create a fully qualified "InterfaceImplementation" that supports both interfaces. However, you are putting it into a declared type of only the first interface. So from the "first" object's perspective, it only cares about anything associated as an IFirstInterface implementation.

Now, on to you second... Even though you've created the object, you can still ask... By the way... are you also a Second Interface? If so, do this...

IFirstInterface first = new InterfaceImplementation();

if( first is ISecondInterface )
  // typecast since the second interface is legit, then call it's method 2
  ((ISecondInterface)first).Method2();

Upvotes: 11

Brian Rasmussen
Brian Rasmussen

Reputation: 116401

The actual type of the instance first points to implements both interface. So obviously both Method1 and Method2 are available on the object.

The static type of first only lets you access Method1. The static type of second only lets you access Method2. I you declare a reference to the object using either of the interfaces, you just select to view the instance as an object fulfilling the selected contract (the interface).

As InterfaceImplementation implements both interfaces, you have the option of referring to the instance using either of the interfaces.

Upvotes: 3

x0n
x0n

Reputation: 52420

Welcome to polymorphism. The object first is always going to be an instance of InterfaceImplementation. How you choose to reference it doesn't affect what the object truly "is." This is how the concept of abstraction works as a whole.

Upvotes: 1

Tim S.
Tim S.

Reputation: 56536

The only thing you're missing is that that's exactly how it's meant to be, and that's a useful feature, not a problem. When casting, you can think of the code as basically saying, "I don't care what I knew this object's type was, I want to see if it can be converted to type T". In this case, since the underlying object is of type InterfaceImplementation, regardless of the fact that it's currently known as an IFirstInterface, the answer is that yes, it can be converted to an ISecondInterface.

Upvotes: 1

csteinmueller
csteinmueller

Reputation: 2487

If you look from the concrete object's point of view, you can say "I'm a IFirstInterface, but I'm also a ISecondInterface". Is that what you mean? The question you described, would end up in casting just inside a inheritance/implementation chain.

Upvotes: 1

Related Questions