Так что я хотел унаследовать от sealed class
в csharp и сгорел. Нет никакого способа распечатать его, если у вас нет доступа к источнику.
Тогда это заставило меня задуматься «почему sealed
вообще существует?». 4 месяца назад. Я не мог понять это, несмотря на чтение многих вещей об этом, таких как:
- Желания Джона Скита « классы были закрыты по умолчанию в .NET ».
- Предпочитаете композицию наследству?
- «Вы не должны запечатывать все классы (...)»
- Как вы издеваетесь над Запечатанным классом?
Я пытался переварить все это с тех пор, но это слишком много для меня. В конце концов, вчера я попробовал это снова. Я снова просмотрел их все, плюс еще несколько:
- Почему класс должен быть чем-то отличным от "абстрактного" или "окончательного / запечатанного"?
- За более чем 15-летний опыт программирования я впервые услышал о SOLID из ответа на вопрос, который уже был связан, и я, очевидно, не читал его всего 4 месяца назад.
Наконец, после долгих размышлений я решил серьезно отредактировать исходный вопрос на основе нового названия.
Старый вопрос был слишком широким и субъективным. В основном спрашивал:
- В старом названии: одна веская причина использовать запечатанный
- В теле: Как правильно модифицировать запечатанный класс? Забыть о наследовании? Использовать композицию?
Но теперь, понимая (что я не сделал вчера), что все sealed
делает, это предотвращает наследование , и мы можем и должны действительно использовать композицию вместо наследования , я понял, что мне нужны были практические примеры.
Я предполагаю, что мой вопрос здесь (и на самом деле всегда был) именно то, что мистер Миндор предложил мне в чате : как разработка наследования может привести к дополнительным затратам?
источник
Ответы:
Это не так сложно понять.
sealed
был создан специально для Microsoft, чтобы сделать их жизнь проще, сэкономить кучу денег и помочь их репутации. Поскольку это языковая функция, ее могут использовать все остальные, но ВАМ, вероятно, никогда не придется использовать запечатанную.Большинство людей жалуются на то, что они не могут продлить класс, и если они это сделают, они скажут, что все знают, что ответственность за правильную работу разработчиков лежит на разработчиках. Это правильно, за исключением тех же людей, которые не имеют ни малейшего понятия об истории Windows, и одна из проблем
sealed
пытается решить.Давайте предположим, что разработчик расширил базовый класс .Net (потому что запечатанный не существует) и заставил его работать идеально. Yay для разработчика. Разработчик доставляет продукт покупателю. Приложение разработчика отлично работает. Клиент счастлив. Жизнь хороша.
Теперь Microsoft выпускает новую операционную систему, которая включает исправление ошибок в этом конкретном базовом классе .Net. Заказчик хочет идти в ногу со временем и выбирает установку новой операционной системы. Внезапно приложение, которое так сильно нравится клиенту, больше не работает, поскольку оно не учитывает ошибки, исправленные в базовом классе .Net.
Кто обвиняет?
Те, кто знаком с историей Microsoft, знают, что виновата будет новая ОС Microsoft, а не прикладное программное обеспечение, которое неправильно использовало библиотеки Windows. Так что теперь Microsoft должна решить проблему, а не компанию, которая ее создала. Это одна из причин, почему код Windows стал раздутым. Из того, что я прочитал, код операционной системы Windows изобилует конкретными проверками if-then, проверяет, работает ли конкретное приложение и версия, и если да, то выполняет некоторую специальную обработку, чтобы позволить программе функционировать. Это огромные деньги, потраченные Microsoft на исправление некомпетентности другой компании.
Использование
sealed
не полностью исключает приведенный выше сценарий, но помогает.источник
sealed
по умолчанию всеми , если не были специально распечатаны, просто потому, что на самом деле очень немногие классы предназначены для наследования. Гораздо более вероятно, что ваш класс не был создан для его поддержки, и вы должны убедиться, что вы потратили это время на разработку, если вы делаете все возможное, чтобы пометить его как незапечатанный.sealed
. Если бы это была фактически опция по умолчанию, то это означало бы, что если бы кто-то наследовал от типа, он бы знал, что он создан для его поддержки.String
затем он мутирует его после проверки безопасности, но до ввода-вывода? Я считаю, что этот тип сценария является причиной того, что JavaString
помеченfinal
(аналогичноsealed
), и я уверен, что та же логика лежит в основе некоторых решений C #.sealed
используется, чтобы указать, что автор класса не разработал его для наследования. Ни меньше, ни больше.Правильное проектирование интерфейса уже достаточно сложно для многих программистов. Правильное проектирование класса, который может быть потенциально унаследован, добавляет сложности и строк кода. Чем больше строк написанного кода, тем больше кода для поддержки. Чтобы избежать этой возрастающей трудности,
sealed
можно показать, что класс никогда не предназначался для наследования, и в этом контексте запечатывание класса является совершенно приемлемым решением проблемы .Представьте себе случай, когда класс
CustomBoeing787
является производным отAirliner
. ЭтоCustomBoeing787
отменяет некоторые защищенные методыAirliner
, но не все из них. Если у разработчика достаточно времени, и оно того стоит, он может провести модульное тестирование класса, чтобы убедиться, что все работает, как ожидается, даже в контексте, когда вызываются неопределяемые методы (например, защищенные установщики, которые изменяют состояние объекта). Если тот же разработчик (1) не имеет времени, (2) не хочет тратить дополнительные сотни или тысячи долларов своего босса / клиента, или (3) не хочет писать дополнительный код, он не нужно прямо сейчас (ЯГНИ), тогда он может:либо выпустить код в открытом виде, как есть, учитывая, что программисты, которые будут поддерживать этот проект позже, будут заботиться о потенциальных ошибках,
или пометьте класс как
sealed
явное указание будущим программистам, что этот класс не предназначен для наследования, и что его распечатывание и использование в качестве родителя должно выполняться на ваш собственный риск.Является ли хорошей идеей запечатать как можно больше классов или как можно меньше? Из моего опыта нет однозначного ответа. Некоторые разработчики склонны использовать
sealed
слишком много; другие не заботятся о том, как класс будет унаследован, и о проблеме, которую он может вызвать. При таком использовании проблема аналогична той, которая заключается в определении, должны ли программисты использовать два или четыре пробела для отступа: правильного ответа нет.источник
tl;dr
здесь. Это либо «Нет, нет ни одной веской причины» , либо «Я думаю, что нет веской причины, но я тоже не знаю». , Для меня «нет окончательного ответа» является одним из тех.sealed
используется, чтобы указать, что автор класса не разработал его для наследования. Это твоя единственная веская причина.String
затем он мутирует его после проверки безопасности, но до ввода-вывода? Я считаю, что этот тип сценария является причиной того, что JavaString
помеченfinal
(аналогичноsealed
), и я уверен, что та же логика лежит в основе некоторых решений C #.Когда класс запечатан, он позволяет коду, использующему этот тип, точно знать, с чем он имеет дело.
Сейчас в C #
string
естьsealed
, вы не можете наследовать от него, но давайте на секунду предположим, что это не так. Если бы вы это сделали, то кто-то мог бы написать такой класс:Теперь это будет строковый класс, который нарушает все виды свойств, о которых дизайнеры
string
знали, что это правда. Они знали, чтоEquals
метод будет переходным, это не так. Черт, этот метод equals даже не симметричен, так как строка может быть равна ему, но она не будет равна этой строке. Я уверен, что есть все виды программистов, которые написали код, предполагая, чтоToString
методstring
не будет генерировать исключение для ненулевых значений. Теперь вы сможете нарушить это предположение.Есть множество других классов, для которых мы могли бы сделать это, и всевозможные предположения, которые мы могли бы нарушить. Если вы удалите функцию языка для
sealed
тогда разработчики языка теперь должны начать учитывать подобные вещи во всем коде своей библиотеки. Они должны выполнять все виды проверок, чтобы гарантировать, что расширенные типы типов, которые они хотят использовать, будут написаны «правильно», что может быть очень дорогостоящим делом (как во время разработки, так и во время выполнения). Имея возможность запечатать класс, они могут гарантировать, что это невозможно, и что любые утверждения, которые они делают о деталях реализации своих собственных типов, не могут быть нарушены, за исключением тех типов, которые специально предназначены для расширения. Для тех типов, которые предназначены для расширения, вы обнаружите, что языковой код должен быть гораздо более осторожным в отношении того, как он работает с ними.источник
sealed
встроенных функций, которые нам не доступны. Это все еще не объясняет, почему его используют вне такой узкой области и, будучи таким же узким, как код компилятора , даже не объясняетsealed
существование.string
Тип не является кодом компилятора. Это часть языкового кода. Полностью отличается. В любом случае, я просто выбрал один пример. Вы можете выбрать практически любой запечатанный класс во всей BCL и использовать его в качестве примера.Enh? Не часто. Я использовал только запечатан , когда у меня есть неизменный тип (или какое - либо другое ограничение) , что на самом деле действительно нужно оставаться незыблемыми и я не могу доверять Наследники к furfill этого требования , не вводя тонкую, catastropic ошибки в систему.
Мы используем наследование для тех вещей, которые не по умолчанию. Даже если композиция предпочтительнее наследования (и это так), это не означает, что наследование следует отбросить. Это означает, что наследование имеет некоторые внутренние проблемы, которые оно вносит в дизайн, а также в удобство сопровождения и компоновки кода, что во многом делает то же самое с (в общем) меньшими проблемами. И это означает, что даже если композиция предпочтительна, наследование хорошо для определенных подгрупп проблем.
Я не хочу быть слишком злым, но если вы только что услышали о SOLID и модульном тестировании, возможно, вам следует выбраться из-под вашего камня и написать код. Вещи не ясны, и редко будет "всегда делать X" или "никогда не использовать Y" или "Z лучше всего" будет правильным способом (как будто вы тяготеете к тому, чтобы основываться на взглядах вашего вопроса). Когда вы пишете код, вы можете видеть случаи, когда это
sealed
может быть хорошо, и случаи, когда это вызывает у вас горе - как и любой другой компромисс.источник
sealed
, пожалуйста?Прежде всего, вы должны прочитать пост Эрика Липперта о том, почему Microsoft закрывает свои уроки.
http://blogs.msdn.com/b/ericlippert/archive/2004/01/22/61803.aspx
Во-вторых, ключевое слово sealed существует для того, чтобы делать именно то, что оно делает - предотвращать наследование. Есть много ситуаций, когда вы хотите предотвратить наследование. Рассмотрим класс, из которого у вас есть коллекция. Если ваш код зависит от того, работает ли этот класс определенным образом, вы не хотите, чтобы кто-то переопределял один из методов или свойств этого класса и вызывал сбой приложения.
В-третьих, использование запечатанного поощряет композицию к наследованию, что является хорошей привычкой. Использование композиции поверх наследования означает, что вы не можете нарушить принцип подстановки Лискова, и вы следуете принципу Open / Closed.
sealed
поэтому это ключевое слово, которое помогает вам следовать двум из пяти самых важных принципов программирования. Я бы сказал, что это делает его очень ценным.источник
Я думаю, что на этот вопрос нет объективного ответа, и что все зависит от вашей точки зрения.
С одной стороны, некоторые люди хотят, чтобы все было «открыто», и бремя обеспечения того, чтобы все работало правильно, ложится на человека, который расширяет класс. Вот почему классы открыты для наследования по умолчанию. И почему все методы Java являются виртуальными по умолчанию.
С другой стороны, некоторые хотят, чтобы все было закрыто по умолчанию, и предоставляют опции для его открытия. В этом случае автор базового класса должен убедиться, что все, что он делает «открытым», безопасно для использования любым возможным способом. Вот почему в C # все методы не являются виртуальными по умолчанию и должны быть объявлены виртуальными для переопределения. Это также для тех людей, которые должны быть способом обойти «открытые» значения по умолчанию. Как сделать класс запечатанным / окончательным, потому что они видят, что кто-то из класса является большой проблемой для дизайна своего класса.
источник
sealed
не может. Как мы можем наследовать от них? Все, что я читаю, мы не можем. Когда-либо. Я не знаю. Я изучал эту тему четыре месяца назад, так как впервые услышал о запечатанном. И я до сих пор не знаю, как сделать это правильно, когда мне нужно что-то изменить в запечатанном классе. Итак, я не вижу «возможности открыть его»!проблема с запечатанным в C # состоит в том, что это довольно окончательно. За 7 лет коммерческой разработки на C # единственное место, где я видел его использование, - это классы Microsoft .NET, где, как мне кажется, у меня была законная причина для расширения рамочного класса для реализации скорректированного поведения, и поскольку класс был запечатан, я не смог ,
Невозможно написать класс, думая обо всех возможных способах его использования и решая, что ни один из них не является законным. Точно так же, если безопасность инфраструктуры зависит от того, что класс не наследуется, у вас есть недостаток дизайна безопасности.
Итак, в заключение, я твердо придерживаюсь мнения, что запечатанный не имеет никакой полезной цели, и ничто из того, что я прочитал здесь до сих пор, не изменило эту точку зрения.
Я могу видеть, что до сих пор было три аргумента, которые оправдывают запечатанные до сих пор.
Аргумент 1 заключается в том, что он устраняет источник ошибок, когда люди наследуют от классов, а затем имеют расширенный доступ к внутренним элементам этого класса, не понимая их должным образом.
Аргумент 2 заключается в том, что если вы расширяете класс Microsoft, а затем Microsoft внедряете исправление ошибки в этом классе, но ваше расширение полагается на эту ошибку, то ваш код теперь сломан, Microsoft получает вину, а запечатывание предотвращает это.
Аргумент 3 заключается в том, что, как разработчик класса, я выбираю, позволять ли вам его расширять, как часть моего дизайна класса.
Аргумент 1 кажется аргументом, что вы, конечный программист, не знаете, как использовать мой код. Это может иметь место, но если вы по-прежнему разрешаете мне доступ к интерфейсу объектов, все равно остается верным, что я использую ваш объект и обращаюсь к нему, не понимая, как его использовать, и, таким образом, могу нанести такой же ущерб , Это слабое обоснование необходимости опечатывания.
Я понимаю, откуда взялась фактическая база для arg 2. В частности, когда Microsoft установила дополнительные проверки ОС на вызовах Win32 API для выявления искаженных вызовов, что улучшило общую стабильность Windows XP по сравнению с Windows NT, но при краткосрочной стоимости многие приложения были сломаны при выпуске Windows XP. Microsoft решила эту проблему, добавив «правила» для этих проверок: игнорировать, когда приложение X нарушает это правило, это известная ошибка
Аргумент 2 является плохим аргументом, потому что в лучшем случае запечатанный в принципе не имеет никакого значения к этому, потому что, если в библиотеке .NET есть ошибка, у вас нет другого выбора, кроме как найти обходной путь, и когда выйдет исправление для Microsoft, вполне вероятно, что означает, что ваша работа, которая зависит от нарушенного поведения, теперь нарушена. Независимо от того, работали ли вы с этим, используя наследование или какой-либо другой дополнительный код-обертку, когда код исправлен, ваша работа будет нарушена.
Аргумент 3 является единственным аргументом, который имеет какое-либо обоснование, чтобы оправдать себя. Но это все еще слабо. Это просто идет вразрез с повторным использованием кода.
источник
It is impossible to write a class thinking about every possible way it could be used
- Именно поэтому многие классы Framework запечатаны ... Это устраняет необходимость думать о том, как кто-то может расширить класс.Я использую только
sealed
ключевые слова в классах, которые содержат только статические методы.источник
static
?Как видно из моего вопроса, я здесь не эксперт. Но я не вижу причин
sealed
даже существовать.Похоже, это сделано для того, чтобы помочь разработчикам кода в разработке интерфейса. Если вы хотите написать класс, который выйдет в дикую природу, и многие люди унаследуют его, изменение чего-либо в этом классе может нарушить его для слишком многих людей. Таким образом, мы можем запечатать это, и никто не может наследовать. "Проблема решена".
Ну, выглядит как «прикрытие пятна и раскрытие другого». И это даже не решение проблемы - это просто устранение инструмента : наследования. Как и любой инструмент, он имеет много применений, и вы рискуете унаследовать от нестабильного класса. Кто бы ни пошел на этот риск, должен знать лучше.
Возможно, здесь может быть ключевое слово
stable
, чтобы люди знали, что от него наследовать безопаснее.источник
sealed
не является полезным инструментом для каркасных дизайнеров. Классы в рамках должны быть черными ящиками; вам не нужно знать о внутренностях класса, чтобы правильно его использовать. Все же это именно то, что требует наследования.