Подтвердить что ты не робот

Почему ключевое слово "запечатанное" существует в .Net?

Большое количество классов в структуре .Net помечены как "запечатанные", что препятствует тому, чтобы вы наследовали эти классы своим. Несомненно, это противоречит природе объектной ориентации, где вы можете расширить и переопределить поведение существующих объектов.

Есть ли веская причина существования ключевого слова "запечатанное"?

В качестве примера, NotifyCollectionChangedEventArgs в Silverlight запечатан. я хотел создайте мою собственную версию ObservableCollection, который поддерживается AddRange и RemoveRange, но Silverlight версия NCCEA не предоставить конструктор, который поддерживает несколько элементов для NewItems и Свойства OldItems, которые уже определены как ILists. Обычно я просто расширьте класс своим вариантом которые перегружают NewItems и Свойства OldItems, но в этом случае Я не могу, и я не вижу причин, почему это должно быть так.

4b9b3361

Ответ 1

Разработка классов (или фреймворков), которые могут быть расширяемыми, не является тривиальным, а просто наследование не является единственным принципом объектно-ориентированного программирования.

Итак, sealed существует, чтобы разработчик/разработчик мог выразить и сохранить эти намерения. Уплотнение класса также может облегчить их жизнь, уменьшив нагрузку на обслуживание. Он позволяет оригинальному разработчику контролировать, как расширяется класс (или фреймворк), чтобы они могли вносить внутренние изменения, не беспокоясь о нарушении изменений кода других.

Один принцип заключается в том, что разработчики должны по умолчанию закрывать любые классы leaf. Затем, когда разработчик намеренно создает незапечатанный класс, он заставляет их думать о расширяемости.


Ссылка: Eric Lippert - Почему так много классов Framework запечатано?

Ответ 2

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

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

Когда ваш класс будет расширенный, вы должны спросить: если разработчик расширяет мой класс и передает этот новый класс для моей библиотеки, могу ли я прозрачно работать с этим новым класс? Могу ли я правильно работать с этим новый класс? Действительно ли этот новый класс будет вести себя одинаково?

Я обнаружил, что большую часть времени Запечатанные классы в .Net Framework иметь под капотом требования, о которых вы не знаете, и что с учетом нынешнего реализация не может быть безопасно подверженных подклассам.

Лисковская подстанция и композиция

Теперь перейдите по этой ссылке и сохраните фактического автора.

Ответ 3

Короткий ответ, потому что Microsoft так сказала. Более длинный ответ заключается в том, что Microsoft предоставила механизм для расширения закрытых классов, называемых методами расширения.

В общем, это плохая идея расширить классы, к которым у вас нет исходного кода. Например, вы не знаете, что метод базового вызова делает для внутренних данных объекта. Да, вы можете использовать отражатель или что-то еще, чтобы понять это, но в целом гораздо лучше использовать композиции или методы расширения.

Вам также необходимо рассмотреть, что такое наследование. Это не просто способ изменить класс, но и обеспечивает полиморфизм. Что, если вы измените семантику, скажем, на класс строки, то вы передаете новый класс строк объекту, который ожидает, что строка будет действовать определенным образом? запечатанный, по сути, принуждает контракт, что этот объект будет всегда работать так, как вы ожидаете.

Ответ 4

Не углубляясь слишком глубоко, понимайте, что Microsoft выступает за герметизацию класса, когда есть потенциальная проблема безопасности, ремонтопригодности или обратной совместимости, с которой ему придется иметь дело с нисходящим потоком. Например, System.String закрывается для обеспечения безопасности и производительности.

В этом конкретном случае вам нужно попросить разработчика Microsoft, почему они решили закрыть этот класс. Тем не менее, литература по архитектурному руководству, которую я читал в последнее время, склоняется к подходу "печати, если вы не знаете , ее нужно будет расширить". Эта литература имеет тенденцию, если это возможно, использовать методы расширения. (Я не говорю, что согласен с этим, я просто говорю, что я читал в последнее время.)

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

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

Ответ 5

Хотя я согласен с тем, что .NET, вероятно, слишком много печатает, он обычно защищает целостность экосистемы. Когда одним из главных приоритетов является сохранение общей структуры/API/времени выполнения, а также некоторые хрупкие взаимозависимости между классами, может быть безопаснее запретить людям отменять это поведение и непреднамеренно дестабилизировать основные функции.

Хотя, опять же, я действительно чувствую, что команда .NET закрывает слишком много классов. Уплотнение иногда может быть простой лень со стороны разработчика, потому что правильный дизайн класса будет слишком большой работой.

Ответ 6

Я бы предположил, что нет веских оснований для уплотнения классов, кроме защиты невежественного, я имею в виду невиновность. Вы знаете старое высказывание: "Дайте им достаточно веревки, и они повесились". Пусть они влияют, я говорю. Возможно, это мой фон на С++, но мне вполне комфортно, зная, что я могу полностью наполнить вещи, если я не стараюсь.

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

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

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

Ответ 7

Это зависит от того, существуют ли классы, которые должны быть просто инстанцированы (наследование, если существует, используется только для упрощения реализации), другие классы предназначены для унаследования, чтобы обеспечить spesific-реализацию.

Запечатанные классы имеют некоторые преимущества:

  • у них нет виртуальных методов, поэтому им не нужно беспокоиться о небезопасных реализованных переопределяющих методах.
  • Если класс неизменен, он может сохранить и гарантировать неизменность.

В противном случае, если вы хотите украсить закрытый класс с помощью методов "комфорт", используйте методы расширения (С# 3.0).

Ответ 8

Просто потому, что что-то является объектом, это не значит, что он всегда должен быть широко открытым для всех, чтобы расширить или переопределить его поведение.

Хорошая аналогия - это дверь и замок. Дверной характер - позволить людям пройти через него, для чего он предназначен. Тем не менее, большинство дверей спроектированы с замками, которые могут ограничить способность людей проходить через них. Решение о том, имеет ли дверь замок и блокировка блокировки по умолчанию, предоставляется архитектору комнаты, исходя из того, что в комнате и у кого есть доступ к ней, а не от того, что это дверь.

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

Ответ 9

Одно из практических применений, в которых я нашел секретное ключевое слово, - это избегать "Хрупких проблем класса". Здесь видео, которое показывает один из хрупких проблем базового класса http://www.youtube.com/watch?v=xnA3RUJcyY4

Позвольте мне пояснить немного подробнее.

Рассмотрим приведенный ниже сценарий, в котором у нас есть родительский класс, называемый "DbParent", с виртуальным методом "Вставка".

класс DbParent {

    public virtual void Insert()
    {
        Console.WriteLine("Parent insert");
    }

}

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

  class DbChildClass : DbParent
  {
  public void  Insert()
    {
        Console.WriteLine("Child inserts");
    }

}

Теперь скажем, через несколько месяцев разработчиков родительского класса развертывания, не понимая влияния на дочерние классы, и добавьте новый метод "Добавить" . Этот метод "Добавить" вызывает метод "Вставить" внутри (ниже приведен фрагмент кода для этого).

  class DbParent
  {
  public  void Add() // Adds method with out consulting
  {
  this.Insert();
  }

  public virtual void Insert()
  {
        Console.WriteLine("Parent insert");
  }
  }

Теперь клиентские программы, которые вызывают метод "Добавить" , создавая объекты дочерних классов, ожидают, что будет выполняться реализация класса "Вставка" класса "Ребенок".

  DbChildClass o = new DbChildClass();
  o.Add();
  Console.Read();

Но whoaaaa, если вы запустите код ниже, вы увидите родительский класс "Вставка", который не ОЖИДАЕТСЯ.

Итак, я бы пошел и пометил класс как "Запечатанный", чтобы избежать таких проблем.