Приведение интерфейса к другому интерфейсу, который он не наследует
Я надеюсь, что кто-то здесь может объяснить, что ошибочные предположения я делаю. В 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. То, как вы решаете ссылаться на него, не влияет на то, что объект действительно "есть".- Вот как работает понятие абстракции в целом.