Приведение интерфейса к другому интерфейсу, который он не наследует

Я надеюсь, что кто-то здесь может объяснить, что ошибочные предположения я делаю. В C# 4.0 у меня есть 2 интерфейса и класс, который реализует их оба. В методе я объявляю переменную с типом первого интерфейса, создаю ее экземпляр, используя класс, который реализует оба интерфейса и может каким-то образом успешно привести ее ко второму интерфейсу, как в следующем коде:

    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();
        }
    }

Я пытаюсь понять, почему кастинг успешно. Да, класс реализует оба интерфейсы, но я бы подумал, что, поскольку первая переменная объявлена как IFirstInterface (которая не наследуется от ISecondInterface), кастинг все равно должен завершиться ошибкой.

Я также попытался реструктурировать свой код другими способами, например, не используя "as", но приведение все еще успешно.

что я упустил?

5 ответов


из вашего примера вы должны быть хороши, тестируя тип type перед вызовом любой из функций. Первое создание создаст полное "InterfaceImplementation", которое поддерживает оба интерфейса. Однако вы помещаете его в объявленный тип только первого интерфейса. Поэтому с точки зрения" первого " объекта он заботится только о чем-либо, связанном с реализацией IFirstInterface.

теперь, на тебе второй... Несмотря на то, что вы создали объект, еще можно спросить... Кстати... вы также второй интерфейс? Если да, сделайте это...

IFirstInterface first = new InterfaceImplementation();

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

фактический тип экземпляра first указывает на реализацию обоих интерфейсов. Так что, очевидно, оба Method1 и Method2 доступны на объекте.

статический тип first только позволяет получить доступ Method1. Статический тип second только позволяет получить доступ Method2. Я объявляю ссылку на объект, используя любой из интерфейсов, вы просто выбираете, чтобы просмотреть экземпляр как объект, выполняющий выбранный контракт (интерфейс).

As InterfaceImplementation реализует оба интерфейса, у вас есть возможность ссылаться на экземпляр с помощью интерфейсов.


единственное, что вам не хватает, это то, что именно так и должно быть, и это полезная функция, а не проблема. При кастинге вы можете думать о коде, как в основном говоря:"мне все равно, что я знал, что тип этого объекта был, я хочу посмотреть, можно ли его преобразовать в тип T". В этом случае, так как базовый объект имеет тип InterfaceImplementation, независимо от того, что в настоящее время он известен как IFirstInterface ответ, что да, он может быть преобразован в ISecondInterface.


Если вы посмотрите с точки зрения конкретного объекта, вы можете сказать: "я IFirstInterface, но я также ISecondInterface". Ты это имеешь в виду? Вопрос, который вы описали, закончится кастингом только внутри цепочки наследования/реализации.


Добро пожаловать в полиморфизм. Объект first всегда будет экземпляром InterfaceImplementation. То, как вы решаете ссылаться на него, не влияет на то, что объект действительно "есть".- Вот как работает понятие абстракции в целом.