Quando e por que você selaria uma classe?

87

Em C # e C ++ / CLI, a palavra-chave sealed(ou NotInheritableem VB) é usada para proteger uma classe de qualquer chance de herança (a classe não será herdável). Eu sei que um recurso da programação orientada a objetos é a herança e acho que o uso de sealedvai contra esse recurso, ele interrompe a herança. Existe um exemplo que mostra o benefício sealede quando é importante usá-lo?

Aan
fonte

Respostas:

96
  1. Em uma classe que implementa recursos de segurança, para que o objeto original não possa ser "personificado".

  2. De modo mais geral, recentemente conversei com uma pessoa da Microsoft, que me disse que tentou limitar a herança aos lugares onde realmente fazia sentido, porque se torna cara em termos de desempenho se não for tratada.
    A palavra-chave selada informa ao CLR que não há nenhuma classe mais abaixo para procurar métodos e isso acelera as coisas.

Na maioria das ferramentas de melhoria de desempenho no mercado hoje em dia, você encontrará uma caixa de seleção que selará todas as suas classes que não são herdadas.
Porém, tenha cuidado, porque se quiser permitir plug-ins ou descoberta de assembly por meio do MEF, você terá problemas.

Louis Kottmann
fonte
3
Eu quis dizer ter cuidado ao selar classes em bibliotecas reutilizadas, especialmente se elas forem reutilizadas por terceiros e, em seguida, reintegradas (via MEF) na base de código. Sua base de código pode não herdar uma determinada classe, mas terceiros sim.
Louis Kottmann
10
O motivo nº 1 parece vago, mas, supondo que não escrevamos "recursos de segurança" na maioria das vezes, isso significa que o motivo nº 1 dificilmente se aplica? A razão 2 é para ajuste de desempenho. De que diferença de desempenho estamos falando? Eles são significativos o suficiente para justificar a alteração da definição de uma classe de não segurança? Mesmo se a resposta fosse "sim", idealmente seria uma opção do compilador, ou seja, "gerar código otimizado para todas as classes não lacradas", em vez de termos que nós, desenvolvedores, alteremos a base do código.
RayLuo
1
torna-se caro em termos de desempenho se não for tratado, isso pode ser medido com menos do que um número insano de testes malucos?
t3chb0t
4
Selar é uma merda. Isso torna o teste mais difícil - eu gostaria de simular algumas classes ASP.NET com FakeItEasy, mas não posso porque elas estão seladas.
Warlike Chimpanzee
2
Não posso concordar mais com @RayLuo. Eu acertei várias vezes que as pessoas selaram suas aulas onde a segurança e o desempenho não são realmente um problema. Seu "lacrado" simplesmente evitou minha necessidade razoável de substituir as classes, tornando as coisas muito mais difíceis. Como Warlike Chimpanzee disse, zombar de uma classe é tão comum em testes.
ZZY
15

Um adendo à excelente resposta de Babuíno :

  1. Se uma classe não for projetada para herança, as subclasses podem quebrar invariantes de classe . Isso realmente só se aplica se você estiver criando uma API pública, é claro, mas como regra geral, selo qualquer classe não explicitamente projetada para ser uma subclasse.

Em uma nota relacionada, aplicável apenas a classes não lacradas: qualquer método criado virtualé um ponto de extensão, ou pelo menos parece que deveria ser um ponto de extensão. Declarar métodos também virtualdeve ser uma decisão consciente. (Em C #, essa é uma decisão consciente; em Java, não.)


EDIT : Alguns links relevantes:

Observe também que Kotlin sela classes por padrão; sua openpalavra-chave é o oposto de Java finalou sealedC # . (Com certeza, não existe um acordo universal de que isso é uma coisa boa .)

Petter Hesselberg
fonte
25
As classes de selagem causam mais dores de cabeça do que benefícios. Eu sempre encontrei situações em que os desenvolvedores selaram classes, causando horas de dificuldade no que deveria ser simples. Pare de selar aulas, você não é tão espirituoso quanto pensa que é. Sele as classes apenas se você DEVE, e mesmo assim, reconsidere. Só minha opinião, como o cara que tem que lidar com classes lacradas de outras pessoas que eu não consigo editar / desmarcar.
Gant Laborde
9
O comentário de @GantMan deve, na verdade, ser considerado uma das respostas à pergunta do OP, porque basicamente dá uma resposta como "Quando? Dificilmente. Por quê? Esta é a razão pela qual você NÃO faz isso." Concordo que você deve postar novamente seu comentário como uma resposta separada e coletar votos para ele. :-)
RayLuo
1
Isso se referia a esta resposta: stackoverflow.com/a/7777674/3195477 ? É melhor vincular a ele do que (apenas) nomear a pessoa
UuDdLrLrSs
2

Marcar uma classe como Sealedimpede a violação de classes importantes que podem comprometer a segurança ou afetar o desempenho.

Muitas vezes, selar uma classe também faz sentido quando se está projetando uma classe de utilitário com comportamento fixo, que não queremos alterar.

Por exemplo, o Systemnamespace em C#fornece muitas classes que são lacradas, como String. Se não fosse lacrado, seria possível estender sua funcionalidade, o que pode ser indesejável, pois é um tipo fundamental com determinada funcionalidade.

Da mesma forma, structuresin C#são sempre selados implicitamente. Portanto, não se pode derivar uma estrutura / classe de outra estrutura. O motivo para isso é que structuressão usados ​​para modelar apenas tipos de dados autônomos, atômicos e definidos pelo usuário , que não queremos modificar.

Às vezes, quando você está construindo hierarquias de classes, você pode querer limitar um determinado ramo na cadeia de herança, com base em seu modelo de domínio ou regras de negócios.

Por exemplo, a Managere PartTimeEmployeesão ambos Employee, mas você não tem nenhuma função depois de funcionários de meio período em sua organização. Nesse caso, você pode querer selar PartTimeEmployeepara evitar mais ramificações. Por outro lado, se você tiver funcionários horistas ou semanais em tempo parcial, pode fazer sentido herdá-los PartTimeEmployee.

Akshay Khot
fonte
Como estender a classe String seria indesejável? String ainda funcionaria exatamente como funciona atualmente, e você poderia ter uma classe derivada com funcionalidade adicional quando desejado, então de que problema você está falando?
Kevin Wells de
Além disso, qual seria o ponto de "limitar" sua hierarquia de herança? Significaria que se você precisasse estender essa hierarquia, teria que abrir a classe pai primeiro, o que é ineficiente
Kevin Wells
Confira este excelente post de Eric Lippert e esta pergunta SO .
Akshay Khot de
1
Mesmo essa resposta basicamente se resume a "Por que você deseja derivar String?", Então menciona as razões pelas quais você pode querer derivar String (strings terminadas em nulo, por exemplo) e diz que você deve apenas contornar isso sem herança. Então, por que torná-lo mais complicado e ter que contornar isso mais tarde, quando você pode simplesmente deixá-lo sem lacre em primeiro lugar e deixar suas opções em aberto
Kevin Wells
Para a segunda pergunta, o objetivo seria evitar comportamentos indesejados (dependendo da lógica de negócios). É mais fácil para unseala classe mais tarde, se necessário, ao invés de lacrá-la e quebrar todas as classes que dependem dela.
Akshay Khot
0

Acho que esse post tem algum ponto bom, o caso específico foi ao tentar lançar uma classe não lacrada para qualquer interface aleatória, o compilador não gera erro; mas quando selado é usado, o compilador gera um erro que não pode ser convertido. Classe selada traz segurança de acesso de código adicional.
https://www.codeproject.com/Articles/239939/Csharp-Tweaks-Why-to-use-the-sealed-keyword-on-cla

strisunshine
fonte
1
Um link para uma solução é bem-vindo, mas certifique-se de que sua resposta seja útil sem ele: adicione contexto ao link para que seus outros usuários tenham uma ideia do que ele é e por que está lá, depois cite a parte mais relevante da página que você ' novo link para caso a página de destino não esteja disponível. Respostas que são pouco mais do que um link podem ser excluídas.
Baum mit Augen
Desculpe, não pretendia postar como resposta, mas parece não ter relação com outras respostas e não sei onde colocá-lo
strisunshine
1
Editei a postagem de acordo com a sugestão. Originalmente, gostaria de contribuir com um ângulo diferente (talvez), mas só recebi um voto negativo e ainda não falamos sobre o conteúdo, o -1 poderia gentilmente informar o motivo?
strisunshine de