Partilhar via


Alterar regras de compatibilidade

Ao longo da sua história, o .NET procurou manter um elevado nível de compatibilidade de versão para versão e entre implementações do .NET. Embora o .NET 5 (e o .NET Core) e versões posteriores possam ser considerados uma tecnologia nova em comparação com o .NET Framework, dois fatores principais limitam a capacidade desta implementação do .NET de divergir do .NET Framework:

  • Um grande número de programadores desenvolveu originalmente ou continua a desenvolver aplicações para o .NET Framework. Esperam um comportamento consistente entre as implementações .NET.
  • Os projetos de bibliotecas .NET Standard permitem aos programadores criar bibliotecas que visam APIs comuns partilhadas pelo .NET Framework e .NET 5 (e .NET Core) e versões posteriores. Os programadores esperam que uma biblioteca usada numa aplicação .NET se comporte de forma idêntica à mesma biblioteca usada numa aplicação .NET Framework.

Juntamente com a compatibilidade entre implementações de .NET, os programadores esperam um elevado nível de compatibilidade entre versões de uma dada implementação de .NET. Em particular, o código escrito para uma versão anterior do .NET Core deve correr sem problemas no .NET 5 ou numa versão posterior. Na verdade, muitos programadores esperam que as novas APIs encontradas nas versões recém-lançadas do .NET também sejam compatíveis com as versões pré-lançamento em que essas APIs foram introduzidas.

Este artigo descreve as alterações que afetam a compatibilidade e a forma como a equipa do .NET avalia cada tipo de alteração. Compreender como a equipa .NET aborda possíveis alterações de emergência é particularmente útil para programadores que abrem pull requests que modificam o comportamento das APIs .NET existentes.

As secções seguintes descrevem as categorias de alterações feitas às APIs .NET e o seu impacto na compatibilidade das aplicações. Mudanças são permitidas (✔️), não permitidas (❌), ou exigem julgamento e uma avaliação de quão previsível, óbvio e consistente era o comportamento anterior (❓).

Observação

  • Para além de servir de guia sobre como as alterações às bibliotecas .NET são avaliadas, os programadores de bibliotecas também podem usar estes critérios para avaliar alterações às suas bibliotecas que visam múltiplas implementações e versões .NET.
  • Para obter informações sobre as categorias de compatibilidade, por exemplo, compatibilidade direta e retroativa, consulte Como as alterações de código podem afetar a compatibilidade.

Alterações ao contrato público

As alterações nesta categoria modificam a área de superfície pública de um tipo. A maioria das alterações nesta categoria não são permitidas, uma vez que violam a compatibilidade com versões anteriores (a capacidade de um aplicativo que foi desenvolvido com uma versão anterior de uma API para executar sem recompilação em uma versão posterior).

Tipos

  • ✔️ PERMITIDO: Removendo uma implementação de interface de um tipo quando a interface já está implementada por um tipo base

  • REQUER JULGAMENTO: Adicionando uma nova implementação de interface a um tipo

    Esta é uma alteração aceitável porque não afeta negativamente os clientes existentes. Quaisquer alterações ao tipo devem funcionar dentro dos limites das alterações aceitáveis aqui definidas para que a nova implementação permaneça aceitável. É necessário extremo cuidado ao adicionar interfaces que afetam diretamente a capacidade de um designer ou serializador de gerar código ou dados que não podem ser consumidos no nível inferior. Um exemplo é a ISerializable interface.

  • REQUER JULGAMENTO: Introdução de uma nova classe base

    Um tipo pode ser introduzido em uma hierarquia entre dois tipos existentes se não introduzir novos membros abstratos ou alterar a semântica ou o comportamento de tipos existentes. Por exemplo, no .NET Framework 2.0, a classe DbConnection tornou-se uma nova classe base para SqlConnection, que anteriormente derivava diretamente de Component.

  • ✔️ PERMITIDO: Mover um tipo de um assembly para outro

    A montagem antiga deve ser marcada com o TypeForwardedToAttribute que aponta para a nova montagem.

  • ✔️ PERMITIDO: Alterar um tipo struct para um tipo readonly struct

    Não é permitido alterar um readonly struct tipo para um struct tipo.

  • ✔️ PERMITIDO: Adicionar a palavra-chave lacrada ou abstrata a um tipo quando não há construtores acessíveis (públicos ou protegidos)

  • ✔️ PERMITIDO: Ampliar a visibilidade de um tipo

  • NÃO permitido: Alterando o namespace ou o nome de um tipo

  • PROIBIDO: Renomear ou remover um tipo público

    Isso quebra todo o código que usa o tipo renomeado ou removido.

    Observação

    Em casos raros, o .NET pode remover uma API pública. Para mais informações, consulte remoção de API no .NET. Para informações sobre a política de apoio da .NET, consulte .NET Política de Apoio.

  • DISALLOWED: Modificação do tipo subjacente de uma enumeração

    Esta é uma mudança de quebra comportamental e em tempo de compilação, bem como uma alteração de quebra binária que pode tornar os argumentos de atributos não analisáveis.

  • NÃO permitido: Selagem de um tipo que foi previamente deslacrado

  • NÃO permitido: Adicionando uma interface ao conjunto de tipos básicos de uma interface

    Se uma interface implementa uma interface que não implementava anteriormente, todos os tipos que implementaram a versão original da interface são quebrados.

  • REQUER JULGAMENTO: Removendo uma classe do conjunto de classes base ou uma interface do conjunto de interfaces implementadas

    Há uma exceção à regra para remoção de interface: você pode adicionar a implementação de uma interface que deriva da interface removida. Por exemplo, você pode remover IDisposable se o tipo ou interface agora implementa IComponent, que implementa IDisposable.

  • PROIBIDO: Mudar um tipo readonly struct para um tipo struct

    No entanto, é permitida a alteração de um struct tipo para um readonly struct tipo.

  • Não permitido: alterar um tipo struct para um tipo ref struct, e vice-versa

  • NÃO PERMITIDO: Redução da visibilidade de um tipo

    No entanto, é permitido aumentar a visibilidade de um tipo.

Membros

  • ✔️ PERMITIDO: Expandir a visibilidade de um membro que não é virtual

  • ✔️ PERMITIDO: Adicionar um membro abstrato a um tipo público que não tenha construtores acessíveis (públicos ou protegidos) ou que o tipo esteja selado

    No entanto, adicionar um membro abstrato a um tipo que tenha construtores acessíveis (públicos ou protegidos) e que não seja sealed não é permitido.

  • ✔️ PERMITIDO: Restringir a visibilidade de um membro protegido quando o tipo não tem construtores acessíveis (públicos ou protegidos) ou o tipo está selado

  • ✔️ PERMITIDO: Mover um membro para uma classe mais alta na hierarquia do que o tipo do qual ele foi removido

  • ✔️ PERMITIDO: Adicionar ou remover uma substituição

    A introdução de uma sobreescrita pode levar os consumidores prévios a ignorar a sobreescrita ao chamar a base.

  • ✔️ ALLOWED: Adicionar um construtor a uma classe, e um construtor sem parâmetros se a classe não tinha construtores anteriormente

    No entanto, não é permitido adicionar um construtor a uma classe que anteriormente não tinha construtores, sem adicionar o construtor sem parâmetros.

  • ✔️ PERMITIDO: Alterar um membro de abstrato para virtual

  • ✔️ PERMITIDO: Alterar de um ref readonly para um ref valor de retorno (exceto para métodos virtuais ou interfaces)

  • ✔️ PERMITIDO: Remover apenas leitura de um campo, caso o tipo estático do campo seja um tipo de valor mutável

  • ✔️ PERMITIDO: Chamar um novo evento que não foi definido anteriormente

  • REQUER JULGAMENTO: Adicionar um novo campo de instância a um tipo

    Essa alteração afeta a serialização.

  • NÃO permitido: Renomeando ou removendo um membro público ou parâmetro

    Isso quebra todo o código que usa o membro renomeado ou removido, ou parâmetro.

    Isso inclui remover ou renomear um getter ou setter de uma propriedade, bem como renomear ou remover membros de enumeração.

  • REQUER JULGAMENTO: Adicionar um membro a uma interface

    Embora seja uma mudança decisiva no sentido em que eleva a versão mínima de .NET para .NET Core 3.0 (C# 8.0), que foi quando foram introduzidos os membros da interface default (DIMs), é permitido adicionar um membro estático, não abstrato e não virtual a uma interface.

    Se você fornecer uma implementação, adicionar um novo membro a uma interface existente não resultará necessariamente em falhas de compilação em assemblies downstream. No entanto, nem todos os idiomas suportam DIMs. Além disso, em alguns cenários, o tempo de execução não pode decidir qual membro da interface padrão invocar. A partir de C# 13, ref struct os tipos podem implementar interfaces, mas não podem ser encaixados ou convertidos num tipo de interface. Portanto, um ref struct tipo deve fornecer uma implementação explícita para cada membro da interface da instância — não pode usar a implementação padrão fornecida pela interface. Adicionar um membro de instância por defeito a uma interface que ref struct implementa requer que ref struct adicione uma implementação correspondente, o que constitui uma alteração de quebra no código fonte. Por esses motivos, use o julgamento ao adicionar um membro a uma interface existente.

    Observação

    Se a sua interface for implementada por ref struct tipos (possível em C# 13 e posteriores), adicionar qualquer membro padrão da instância à interface é uma alteração que quebra a fonte para esses chamadores. Deve ref struct fornecer uma implementação explícita do novo membro; não pode recorrer à implementação padrão.

  • NÃO permitido: Alterando o valor de uma constante pública ou membro de enumeração

  • NÃO permitido: Alterar o tipo de uma propriedade, campo, parâmetro ou valor de retorno

  • NÃO permitido: Adicionar, remover ou alterar a ordem dos parâmetros

  • É proibido adicionar ou remover a palavra-chave in, out ou ref de um parâmetro

  • ✔️ PERMITIDO: Alterar um ref parâmetro para ref readonly

    Alterar um parâmetro de ref para ref readonly é compatível com o código fonte dos sites de chamadas existentes que passam argumentos com o modificador ref. Essas chamadas continuam a compilar sem qualquer alteração. Ao contrário de mudar ref para in, um ref readonly parâmetro não permite silenciosamente que os chamadores passem rvalues (não variáveis); o compilador emite um aviso se o argumento não for uma variável. Os locais de chamadas existentes ref mantêm-se válidos.

  • DESAUTORIZADO: Alterar um in parâmetro para ref readonly

    Sites de chamadas que passam in argumentos sem o in modificador (que o compilador permite para in parâmetros) receberão um aviso quando o parâmetro mudar para ref readonly, porque ref readonly requer que o argumento seja passado por referência. Os chamadores que consideram os avisos como erros vão experienciar uma alteração que quebra a fonte.

  • NÃO PERMITIDO: Renomear um parâmetro (incluindo a alteração de maiúsculas e minúsculas)

    Isto é considerado uma ruptura por dois motivos:

  • NÃO permitido: Alterar de um ref valor de retorno para um ref readonly valor de retorno

  • ❌️ NÃO permitido: Alterar de um ref readonly para um ref valor de retorno em um método ou interface virtual

  • NÃO permitido: Adicionar ou remover resumo de um membro

  • PROIBIDO: Remover a palavra-chave virtual de um membro

  • NÃO permitido: Adicionar a palavra-chave virtual a um membro

    Embora isso geralmente não seja uma alteração importante porque o compilador C# tende a emitir instruções callvirt na Linguagem Intermediária (IL) para chamar métodos não virtuais (callvirt executa uma verificação de nulidade, enquanto uma chamada normal não), esse comportamento não é imutável por vários motivos:

    • C# não é a única linguagem que o .NET suporta.
    • O compilador C# tenta cada vez mais otimizar callvirt para uma chamada normal sempre que o método de destino é não-virtual e provavelmente não é nulo (como um método acessado através do operador de propagação nula ?.).

    Tornar um método virtual implica que o código do consumidor, na maioria das vezes, acaba chamando-o de modo não virtual.

  • NÃO permitido: Fazer um resumo de membro virtual

    Um membro virtual fornece uma implementação de método que pode ser substituída por uma classe derivada. Um membro abstrato não fornece implementação e deve ser substituído.

  • Proibido: Adicionar a palavra-chave sealed a um membro da interface

    Adicionar sealed a um membro da interface padrão o tornará não virtual, impedindo que a implementação de um tipo derivado desse membro seja chamada.

  • NÃO permitido: Adicionar um membro abstrato a um tipo público que tenha construtores acessíveis (públicos ou protegidos) e que não esteja selado

  • NÃO permitido: Adicionar ou remover a palavra-chave estática de um membro

  • NÃO permitido: Adicionar uma sobrecarga que impede uma sobrecarga existente e define um comportamento diferente

    Isso prejudica os clientes existentes que estavam vinculados ao limite de capacidade anterior. Por exemplo, se uma classe tiver uma única versão de um método que aceita UInt32, um consumidor existente conseguirá vincular-se a essa sobrecarga ao fornecer um valor Int32. No entanto, se você adicionar uma sobrecarga que aceita um Int32, ao recompilar ou usar a ligação tardia, o compilador agora se liga à nova sobrecarga. Se resultar em comportamentos diferentes, isto pode ser uma mudança decisiva.

  • REQUER JULGAMENTO: Adicionar OverloadResolutionPriorityAttribute a uma sobrecarga existente ou alterar o seu valor de prioridade

    Isto OverloadResolutionPriorityAttribute afeta a resolução de sobrecarga ao nível da fonte: os chamadores que recompilam podem resolver para uma sobrecarga diferente da anterior. O uso pretendido é adicionar o atributo a uma nova, melhor sobrecarga, para que o compilador a prefira em relação às já existentes. Adicioná-lo a uma sobrecarga existente ou alterar o valor de prioridade numa sobrecarga já atribuída pode ser uma alteração que quebra a fonte, porque os chamadores que recompilam podem alterar o comportamento.

  • ✔️ PERMITIDO: Adicionar a allows ref struct contrarrestrição a um parâmetro de tipo genérico

    A adição de allows ref struct permite expandir os tipos que podem ser usados como argumentos de tipo ao permitir tipos ref struct. Os chamadores existentes que usam argumentos de tipo diferente de "ref struct" não são afetados. O método genérico ou tipo deve seguir as regras de segurança de referência para todas as instâncias do parâmetro de tipo.

  • PROIBIDO: Remoção da allows ref struct anti-restrição de um parâmetro de tipo genérico

    Remover allows ref struct restringe que tipos os chamadores podem usar como argumentos de tipo. Qualquer chamador que passe um argumento ref struct como tipo não irá mais compilar.

  • DISALLOWED: Adição de um construtor a uma classe que antes não tinha construtor sem adicionar o construtor sem parâmetros

  • ❌️ NÃO PERMITIDO: Acrescentar somente leitura a um campo

  • NÃO permitido: Reduzir a visibilidade de um membro

    Isso inclui reduzir a visibilidade de um membro protegido quando existem construtores acessíveis (public ou protected) e o tipo não está selado. Se não for esse o caso, é permitida a redução da visibilidade de um membro protegido.

    É permitido aumentar a visibilidade de um membro.

  • NÃO permitido: Alterar o tipo de membro

    O valor de retorno de um método ou o tipo de uma propriedade ou campo não pode ser modificado. Por exemplo, a assinatura de um método que retorna um Object não pode ser alterada para retornar um String, ou vice-versa.

  • DISALLOWED: Adicionando um campo de instância a uma struct que não tem campos não públicos

    Se uma struct tiver apenas campos públicos ou não tiver campos, os chamadores podem declarar variáveis locais desse tipo de struct sem chamar o construtor da struct ou inicializar primeiro a variável local para default(T), desde que todos os campos públicos sejam configurados na struct antes do primeiro uso. Adicionar quaisquer novos campos - públicos ou não públicos - a tal struct é uma alteração de quebra de fonte para esses chamadores, pois o compilador agora exigirá que os campos adicionais sejam inicializados.

    Além disso, adicionar quaisquer novos campos - públicos ou não públicos - a uma estrutura sem campos ou apenas campos públicos é uma alteração de quebra binária para chamadores que se aplicaram [SkipLocalsInit] ao seu código. Como o compilador não estava ciente destes campos em tempo de compilação, ele poderia produzir IL que não inicializa totalmente a estrutura, levando à criação da estrutura a partir de dados de pilha não inicializados.

    Se uma struct tiver campos não públicos, o compilador já impõe a inicialização através do construtor ou default(T), e adicionar novos campos de instância não é uma mudança disruptiva.

  • NÃO permitido: Disparar um evento existente quando ele nunca foi disparado antes

Mudanças comportamentais

Assemblagens

  • ✔️ PERMITIDO: Tornar um conjunto portátil quando as mesmas plataformas ainda são suportadas

  • PROIBIDO: Alterar o nome de um assembly

  • NÃO PERMITIDO: Alterar a chave pública de uma assembly

Propriedades, campos, parâmetros e valores de retorno

  • ✔️ PERMITIDO: Alterar o valor de uma propriedade, campo, valor de retorno ou parâmetro out para um tipo mais derivado

    Por exemplo, um método que retorna um tipo de Object pode retornar uma String instância. (No entanto, a assinatura do método não pode ser alterada.)

  • ✔️ PERMITIDO: Aumentar o intervalo de valores aceitos para uma propriedade ou parâmetro se o membro não for virtual

    Enquanto o intervalo de valores que podem ser passados para o método ou são retornados pelo membro pode expandir, o parâmetro ou tipo de membro não pode. Por exemplo, enquanto os valores passados para um método podem se expandir de 0-124 para 0-255, o tipo de parâmetro não pode mudar de Byte para Int32.

  • NÃO permitido: Aumentar o intervalo de valores aceitos para uma propriedade ou parâmetro se o membro for virtual

    Esta alteração afeta os membros já substituídos, o que significa que eles não funcionarão corretamente para o intervalo estendido de valores.

  • NÃO permitido: Diminuindo o intervalo de valores aceitos para uma propriedade ou parâmetro

  • NÃO permitido: Aumentando o intervalo de valores retornados para uma propriedade, campo, valor de retorno ou parâmetro de saída

  • PROIBIDO: Modificar os valores devolvidos de uma propriedade, campo, valor de retorno de método ou parâmetro out

  • NÃO permitido: alterando o valor padrão de uma propriedade, campo ou parâmetro

    Alterar ou remover um valor padrão de parâmetro não é uma quebra binária. Remover um valor padrão de parâmetro é uma quebra de origem, e alterar um valor padrão de parâmetro pode resultar em uma quebra comportamental após a recompilação.

    Por esse motivo, a remoção de valores padrão de parâmetros é aceitável no caso específico de "mover" esses valores padrão para uma nova sobrecarga de método para eliminar a ambiguidade. Por exemplo, considere um método MyMethod(int a = 1)existente . Se você introduzir uma sobrecarga de MyMethod com dois parâmetros a opcionais e b, poderá preservar a compatibilidade movendo o valor padrão de a para a nova sobrecarga. Agora as duas sobrecargas são MyMethod(int a) e MyMethod(int a = 1, int b = 2). Este padrão permite MyMethod() compilar.

  • NÃO permitido: Alterando a precisão de um valor de retorno numérico

  • REQUER JULGAMENTO: Uma alteração na análise de entrada e lançamento de novas exceções (mesmo que o comportamento de análise não esteja especificado na documentação

  • NÃO PERMITIDO: Adição ou remoção de tipos de casos de uma union declaração

    Adicionar ou remover um tipo de caso de um tipo union é simultaneamente uma quebra binária e uma quebra de código.

    Os testes de correspondência de padrões deixam de ser exaustivos após a adição de um tipo de caso. O compilador sinaliza as expressões de correspondência de padrões como não exaustivas. Em tempo de execução, valores inesperados causam exceções em tempo de execução. Remover um tipo de caso remove a declaração do construtor para esse tipo de caso.

Exceções

  • ✔️ PERMITIDO: Lançar uma exceção mais derivada do que uma exceção existente

    Como a nova exceção é uma subclasse de uma exceção existente, o código de tratamento de exceção anterior continua a manipular a exceção. Por exemplo, no .NET Framework 4, os métodos de criação e recuperação de cultura começaram a lançar um CultureNotFoundException em vez de um ArgumentException se a cultura não fosse encontrada. Porque CultureNotFoundException deriva de ArgumentException, esta é uma mudança aceitável.

  • ✔️ PERMITIDO: Lançar uma exceção mais específica do que NotSupportedException, NotImplementedException, NullReferenceException

  • ✔️ PERMITIDO: Lançar uma exceção que é considerada irrecuperável

    As exceções irrecuperáveis não devem ser interceptadas, mas sim ser processadas por um handler de nível superior. Portanto, não se espera que os usuários tenham um código que detete essas exceções explícitas. As exceções irrecuperáveis são:

  • ✔️ PERMITIDO: Lançar uma nova exceção em um novo caminho de código

    A exceção deve aplicar-se apenas a um novo caminho de código que é executado com novos valores de parâmetro ou estado e que não pode ser executado pelo código existente destinado à versão anterior.

  • ✔️ PERMITIDO: Removendo uma exceção para permitir um comportamento mais robusto ou novos cenários

    Por exemplo, um Divide método que anteriormente só manipulava valores positivos e lançava um ArgumentOutOfRangeException de outra forma pode ser alterado para suportar valores negativos e positivos sem lançar uma exceção.

  • ✔️ PERMITIDO: Alterar o texto de uma mensagem de erro

    Os desenvolvedores não devem confiar no texto das mensagens de erro, que também mudam com base na cultura do usuário.

  • NÃO permitido: Lançar uma exceção em qualquer outro caso não listado acima

  • NÃO permitido: Remoção de uma exceção em qualquer outro caso não listado acima

Atributos

  • ✔️ PERMITIDO: Alterar o valor de um atributo que não é observável

  • NÃO permitido: Alterando o valor de um atributo que é observável

  • REQUER JULGAMENTO: Removendo um atributo

    Na maioria dos casos, remover um atributo (como NonSerializedAttribute) é uma alteração crítica.

Suporte da plataforma

  • ✔️ PERMITIDO: Suporte a uma operação em uma plataforma que anteriormente não era suportada

  • NÃO permitido: Não suporta ou agora requer um service pack específico para uma operação que anteriormente era suportada em uma plataforma

Alterações à implementação interna

  • REQUER JULGAMENTO: Alterar a área de superfície de um tipo interno

    Tais mudanças são geralmente permitidas, embora quebrem a reflexão privada. Em alguns casos, quando bibliotecas populares de terceiros ou um grande número de desenvolvedores dependem das APIs internas, essas alterações podem não ser permitidas.

  • REQUER JULGAMENTO: Alterar a implementação interna de um membro

    Estas alterações são geralmente permitidas, embora quebrem a reflexão privada. Em alguns casos, quando o código do cliente depende frequentemente de uma reflexão privada ou quando a alteração introduz efeitos secundários não intencionais, estas alterações podem não ser permitidas.

  • ✔️ PERMITIDO: Melhorar o desempenho de uma operação

    A capacidade de modificar o desempenho de uma operação é essencial, mas tais alterações podem quebrar o código que depende da velocidade atual de uma operação. Isso é particularmente verdadeiro para o código que depende do tempo das operações assíncronas. A alteração de desempenho não deve ter efeito sobre outros comportamentos da API em questão; caso contrário, a mudança resultará numa incompatibilidade.

  • ✔️ PERMITIDO: Alterar indiretamente (e muitas vezes adversamente) o desempenho de uma operação

    Se a mudança em questão não for categorizada como quebra por algum outro motivo, isso é aceitável. Muitas vezes, ações precisam ser tomadas que podem incluir operações extras ou que adicionam novas funcionalidades. Isso quase sempre afetará o desempenho, mas pode ser essencial para fazer a API em questão funcionar conforme o esperado.

  • DISALLOWED: Alterando uma API síncrona para assíncrona (e vice-versa)

Alterações de código

  • ✔️ PERMITIDO: Adicionando params a um parâmetro

  • NÃO permitido: Alterando uma struct para uma classe e vice-versa

  • NÃO PERMITIDO: Adicionar a instrução checked a um bloco de código

    Essa alteração pode fazer com que o código executado anteriormente lance um OverflowException e é inaceitável.

  • NÃO permitido: Removendo parâmetros de um parâmetro

  • DESAUTORIZADO: Alterar o tipo de coleção de um params parâmetro

    A partir do C# 13, os parâmetros params suportam tipos de coleção que não são arrays, incluindo Span<T>, ReadOnlySpan<T>, tipos struct ou de classe que implementem IEnumerable<T> com um construtor acessível sem argumentos e um método de instância Add, e tipos de interface específicos como IList<T>. Alterar o tipo de coleção de um parâmetro existente params (por exemplo, de params T[] para params ReadOnlySpan<T>) altera a assinatura IL do método e constitui uma alteração binária disruptiva. As invocações compiladas contra a versão anterior devem ser recompiladas.

  • ✔️ PERMITIDO: Converter um método de extensão para a sintaxe dos membros do bloco de extensão

    A partir do C# 14, pode declarar membros de extensão usando blocos extension, além de utilizar a sintaxe de parâmetros antigos this. Ambos os formulários geram IL idêntico, por isso os chamadores não conseguem distinguir entre eles. Converter métodos de extensão existentes para a nova sintaxe de blocos de extensão é compatível com binário e código-fonte.

  • Não permitido: Alterar a ordem em que os eventos são disparados

    Os desenvolvedores podem razoavelmente esperar que os eventos sejam acionados na mesma ordem, e o código do desenvolvedor frequentemente depende da ordem em que os eventos são disparados.

  • Não permitido: Remover a ativação de um evento numa determinada ação

  • NÃO permitido: Alterar o número de vezes que determinados eventos são chamados

  • NÃO PERMITIDO: Adicionar o FlagsAttribute a um tipo de enumeração

Ver também