Наследование: внутренний класс против внутреннего интерфейса - PullRequest
0 голосов
/ 16 октября 2018

Выражая озабоченность по поводу предотвращения воздействия базовых классов , я узнал (через тестирование), что класс public не может наследоваться от класса internal;однако класс public может наследоваться от интерфейса internal.Мне действительно любопытно, почему это возможно.Я полагаю, что это может быть связано с одним (или любой комбинацией) следующего:

  1. Интерфейс просто содержит сигнатуры, которые должны быть реализованы.
  2. Класс может иметь свойства, методыи т. д., к которым можно получить доступ через производный тип.
  3. В классе могут быть методы, которые могут быть переопределены производными типами.

Случай 1

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


Case 2 и 3

В отличие от interfaces,классы могут иметь свойства public, к которым могут обращаться производные типы.Например:

private class A {
    public int SomeProperty { get; set; } = 0;
}
public class B : A {
    // Some cool code.
}
public class C : B {
    public int MyInt => SomeProperty;
}

Эта структура имеет противоречивую доступность, поскольку SomeProperty имеет значение public и доступна для всех производных типов;таким образом, A и B должны иметь одинаковые уровни доступа для предотвращения воздействия.


Это причина, по которой класс public может быть производным от internal interface, но не internal classили я что-то упустил?Кроме того, есть ли другие причины, по которым это возможно?


Примечание

Я не ищу основанный на мнении ответ;Я ищу технически правильную причину, по которой это возможно.

Это не дубликат, поскольку я хотел найти причину, по которой вы не можете получить производное от одного, а можете другое.

1 Ответ

0 голосов
/ 23 октября 2018

Я думаю, что ключевая концепция, которую вам не хватает, - это разница между наследованием и реализацией интерфейса.

Когда класс наследует другой класс, это означает, что это в основном более специфический тип базового класса - например,собака - это особый тип животного, поэтому, когда у вас есть такие классы, как:

class Animal {/* implementation here */}
class Dog : Animal {/* dog implementation here */}

Класс Dog уже содержит все реализации Animal, кроме его конструкторов (статических и экземпляров) иФинализаторы.

Однако, когда класс реализует интерфейс, это означает, что он должен предоставлять члены указанного интерфейса (а именно метод, свойства, события и индексаторы), поэтому, если у вас есть интерфейс IAnimal иКласс Dog, реализующий его напрямую, ваш код выглядит следующим образом:

interface IAnimal 
{
    void Eat();
}

class Dog : IAnimal 
{
    public void Eat() {/* implementation here */}
}

Обратите внимание, что все, что объявляет IAnimal, должно быть реализовано, явно или неявно, в классе Dog, поэтомуКонтракт, предоставленный интерфейсом, сохраняется в классе - независимо от того, является ли пользовательlass знает интерфейс или нет.

Итак, в заключение - чтобы использовать класс, вам не нужно ничего знать об интерфейсах, которые он реализует, но вам нужно знать все, что является классом, и посколькуСобака - это животное, если собака общедоступна, то же самое должно быть и с животным.
Интерфейс IAnimal, с другой стороны, может оставаться внутренним.

Еще один момент о реализации внутренних интерфейсов, уже упомянутый вкомментарии к вопросу от пользователя 2864740 - Поскольку все неявные реализации интерфейса должны быть открытыми - если вы реализуете внутренний интерфейс, вам следует рассмотреть возможность явной его реализации - таким образом, реализация остается внутренней и не раскрывается вневмещающий узел.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...