Compartilhar via


Alterar regras para compatibilidade

Ao longo de seu histórico, .NET tentou manter um alto nível de compatibilidade de versão para versão e entre implementações de .NET. Embora .NET 5 (e .NET Core) e versões posteriores possam ser consideradas como uma nova tecnologia em comparação com .NET Framework, dois fatores principais limitam a capacidade dessa implementação de .NET de divergir do .NET Framework:

  • Um grande número de desenvolvedores originalmente desenvolveram ou ainda desenvolvem aplicativos do .NET Framework. Eles esperam um comportamento consistente entre implementações .NET.
  • .NET projetos de biblioteca Standard permitem que os desenvolvedores criem bibliotecas que visam APIs comuns compartilhadas pelo .NET Framework e .NET 5 (e .NET Core) e versões posteriores. Os desenvolvedores esperam que uma biblioteca usada em um aplicativo .NET se comporte de forma idêntica à mesma biblioteca usada em um aplicativo .NET Framework.

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

Este artigo descreve as alterações que afetam a compatibilidade e a maneira como a equipe de .NET avalia cada tipo de alteração. Entender como a equipe de .NET aborda possíveis alterações interruptivas é particularmente útil para desenvolvedores que abrem solicitações de pull que modificam o comportamento das APIs de .NET existentes.

As seções a seguir descrevem as categorias de alterações feitas em APIs de .NET e seu impacto na compatibilidade do aplicativo. As alterações 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

  • Além de servir como um guia de como as alterações nas bibliotecas de .NET são avaliadas, os desenvolvedores de biblioteca também podem usar esses critérios para avaliar as alterações em suas bibliotecas direcionadas a várias .NET implementações e versões.
  • Para obter informações sobre as categorias de compatibilidade, por exemplo, compatibilidade com versões anteriores e futuras, consulte Como as alterações de código podem afetar a compatibilidade.

Modificações no contrato público

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

Tipos

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

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

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

  • REQUER JULGAMENTO: Introdução a 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 dos 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

    O assembly antigo precisa ser marcado com o TypeForwardedToAttribute que aponta para o novo assembly.

  • ✔️ PERMITIDO: alterar um tipo de struct para um tipo readonly struct

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

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

  • ✔️ PERMITIDO: Expansão da visibilidade de um tipo

  • NÃO PERMITIDO: alterar o namespace ou nome de um tipo

  • NÃO PERMITIDO: renomear ou remover um tipo público

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

    Observação

    Em casos raros, .NET pode remover uma API pública. Para obter mais informações, consulte remoção de API em .NET. Para obter informações sobre a política de suporte do .NET, consulte .NET Support Policy.

  • NÃO PERMITIDO: Alterar o tipo subjacente de uma enumeração

    Esta é uma alteração significativa de tempo de compilação e comportamental, bem como uma alteração significativa binária que pode tornar os argumentos de atributo inseparáveis.

  • NÃO PERMITIDO: selar um tipo que estava sem selo

  • DISALLOWED: Adicionar uma interface ao conjunto de tipos base de uma interface

    Se uma interface passar a implementar uma interface que anteriormente não implementava, todos os tipos que implementaram a versão original da interface ficarão incompatíveis.

  • 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.

  • NÃO PERMITIDO: alterar um tipo readonly struct para um tipo struct

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

  • NÃO PERMITIDO: alterar um tipo struct para um ref struct e vice-versa

  • NÃO PERMITIDO: reduzir a visibilidade de um tipo

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

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 seja lacrado

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

  • ✔️ PERMITIDO: Restringir a visibilidade de um membro protegido quando o tipo não tiver construtores acessíveis (públicos ou protegidos) ou se o tipo estiver lacrado

  • ✔️ 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 substituição pode fazer com que os consumidores anteriores pulem a substituição ao chamar a base.

  • ✔️ PERMITIDO: Adicionar um construtor a uma classe, juntamente com um construtor sem parâmetros se a classe anteriormente não tivesse construtores

    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: Alterando um membro de abstrato para virtual

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

  • ✔️ PERMITIDO: Remover readonly de um campo, a menos que 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: renomear ou remover um membro ou parâmetro público

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

    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 alteração significativa no sentido de que ele eleva sua versão mínima de .NET para .NET Core 3.0 (C# 8.0), que é quando membros de interface padrão (DIMs) foram introduzidos, é 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 necessariamente resultará em falhas de compilação em assemblies downstream. No entanto, nem todos os idiomas dão suporte a DIMs. Além disso, em alguns cenários, o runtime não pode decidir qual membro de interface padrão invocar. A partir do C# 13, os ref struct tipos podem implementar interfaces, mas não podem ser classificados ou convertidos em um tipo de interface. Portanto, um ref struct tipo deve fornecer uma implementação explícita para cada membro da interface de instância , ele não pode usar a implementação padrão fornecida pela interface. Adicionar um membro de instância padrão a uma interface que um ref struct implementa exige que ref struct adicione uma implementação correspondente, o que é uma mudança que quebra a compatibilidade do código-fonte. Por esses motivos, use o julgamento ao adicionar um membro a uma interface existente.

    Observação

    Se a interface for implementada por tipos ref struct (possível no C# 13 e posterior), adicionar qualquer membro de instância padrão à interface será uma alteração incompatível para esses chamadores. Ele ref struct deve fornecer uma implementação explícita do novo membro; ele não pode voltar à implementação padrão.

  • NÃO PERMITIDO: Alteração do valor de uma constante pública ou membro de enumeração

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

  • NÃO PERMITIDO: adicionar, remover ou alterar a ordem dos parâmetros

  • NÃO PERMITIDO: 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 para pontos de chamada existentes que passam argumentos com o modificador ref – essas chamadas continuam a compilar sem alterações. Ao contrário da alteração de ref para in, um parâmetro ref readonly não permite implicitamente que chamadas passem rvalues (não variáveis); o compilador emitirá um aviso se o argumento não for uma variável. Os pontos de chamada existentes ref permanecem válidos.

  • NÃO PERMITIDO: Alterando um in parâmetro para ref readonly

    Chamadas de sites que passam in argumentos sem o modificador in (que o compilador permite para parâmetros in) receberão um aviso quando o parâmetro for alterado para ref readonly, pois ref readonly requer que o argumento seja passado por referência. Os chamadores que tratam avisos como se fossem erros terão uma alteração que quebra o código-fonte.

  • NÃO PERMITIDO: renomear um parâmetro (incluindo alterar a capitalização)

    Isso é considerado interrupção por dois motivos:

  • NÃO PERMITIDO: alterar de um valor de retorno ref para um valor de retorno ref readonly

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

  • NÃO PERMITIDO: adicionar ou remover abstract de um membro

  • NÃO PERMITIDO: remover a palavra-chave virtual de um membro

  • PROIBIDO: Adicionar a palavra-chave virtual a um membro

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

    • 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 por meio do operador de propagação ?. null).

    Tornar um método virtual significa que o código do consumidor em geral acabaria chamando-o não virtualmente.

  • NÃO PERMITIDO: transformar um membro virtual em abstrato

    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 nenhuma implementação e deve ser substituído.

  • NÃO PERMITIDO: adicionando a palavra-chave sealed a um membro da interface

    Adicionar sealed a um membro de 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 não seja sealed

  • NÃO PERMITIDO: Adicionar ou remover a palavra-chave static de um membro

  • NÃO PERMITIDO: adicionar uma sobrecarga que impede uma sobrecarga existente e define um comportamento diferente

    Isso interrompe os clientes existentes que estavam vinculados à sobrecarga anterior. Por exemplo, se uma classe tiver uma única versão de um método que aceite um UInt32, um consumidor existente será vinculado a essa sobrecarga ao passar um valor Int32. No entanto, se você adicionar uma sobrecarga que aceita um Int32, ao recompilar ou usar associação tardia, o compilador agora se associa à nova sobrecarga. Se resultar em um comportamento diferente, isso pode ser uma alteração disruptiva.

  • REQUER JULGAMENTO: Adicionando OverloadResolutionPriorityAttribute a uma sobrecarga existente ou alterando seu valor de prioridade

    O OverloadResolutionPriorityAttribute afeta a resolução de sobrecarga no nível de código-fonte: os chamadores que recompilam podem resultar em uma sobrecarga diferente da anterior. O uso pretendido é adicionar o atributo a uma sobrecarga nova e melhor para que o compilador prefira-o em vez dos existentes. Adicioná-lo a uma sobrecarga existente ou alterar o valor de prioridade de uma sobrecarga já atribuída pode causar uma mudança que quebra a compatibilidade, pois os chamadores que recompilarem o código podem alterar o comportamento.

  • ✔️ PERMITIDO: Adicionar a "anti-restrição" a um parâmetro de tipo genérico

    Ao adicionar allows ref struct, expande-se quais tipos podem ser usados como argumentos de tipo, permitindo que tipos ref struct sejam utilizados. Os chamadores existentes que usam argumentos de tipo diferente ao ref struct não são afetados. O método ou tipo genérico deve seguir as regras de segurança de referência para todas as instâncias desse parâmetro de tipo.

  • NÃO PERMITIDO: Removendo a allows ref struct contra-restrição de um parâmetro de tipo genérico

    A remoção allows ref struct restringe quais tipos os chamadores podem usar como argumentos de tipo. Qualquer chamador que passar um ref struct como argumento de tipo não será mais compilável.

  • NÃO PERMITIDO: adicionar um construtor a uma classe que anteriormente não tinha construtor sem adicionar o construtor sem parâmetros

  • ❌️ NÃO PERMITIDO: adicionar readonly a um campo

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

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

    É permitido aumentar a visibilidade de um membro.

  • NÃO PERMITIDO: alterar o tipo de um membro

    O valor retornado 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 Stringou vice-versa.

  • PROIBIDO: adicionar um campo de instância a um struct que não contém campos não públicos

    Se um struct tiver somente campos públicos ou não tiver nenhum campo, os chamadores poderão declarar locais desse tipo de struct sem chamar o construtor dele ou inicializar primeiro o local como default(T), desde que todos os campos públicos sejam definidos no struct antes do primeiro uso. Adicionar campos públicos ou não públicos ao struct é uma alteração interruptiva de fonte para esses chamadores, pois o compilador agora exigirá que os campos adicionais sejam inicializados.

    Além disso, adicionar novos campos - sejam eles públicos ou privados - a uma estrutura sem campos ou com apenas campos públicos é uma alteração que quebra a compatibilidade binária para os usuários que aplicaram [SkipLocalsInit] ao seu código. Como o compilador não estava ciente desses campos no tempo de compilação, ele poderia emitir IL, que não inicializa totalmente o struct e faz com que ele seja criado com base em dados de pilha não inicializados.

    Se um struct tiver campos não públicos, o compilador já imporá a inicialização por meio do construtor ou default(T), e adicionar novos campos de instância não será uma alteração significativa.

  • NÃO PERMITIDO: disparar um evento existente quando ele nunca foi disparado antes

Alterações comportamentais

Assembléias

  • ✔️ PERMITIDO: tornar um assembly portátil quando ainda há suporte para as mesmas plataformas

  • PROIBIDO: Alterar o nome de um componente

  • NÃO PERMITIDO: alterar a chave pública de um assembly

Propriedades, campos, parâmetros e valores retornados

  • ✔️ PERMITIDO: alterando o valor de uma propriedade, campo, valor retornado 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: Aumentando o intervalo de valores aceitos para uma propriedade ou parâmetro se o membro não for virtual

    Embora o intervalo de valores que podem ser passados para o método ou retornados pelo membro possa ser expandido, o parâmetro ou tipo de membro não pode. Por exemplo, embora os valores passados para um método possam ser expandidos de 0 a 124 para 0 a 255, o tipo de parâmetro não pode ser alterado de Byte para Int32.

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

    Essa alteração interrompe os membros substituídos existentes, que não funcionarão corretamente para o intervalo estendido de valores.

  • NÃO PERMITIDO: reduzir o intervalo de valores aceitos de uma propriedade ou parâmetro

  • NÃO PERMITIDO: aumentar o intervalo de valores retornados de uma propriedade, campo, valor de retorno ou parâmetro out

  • NÃO PERMITIDO: alterar os valores retornados de uma propriedade, campo, valor de retorno ou parâmetro out

  • PROIBIDO: Alterar 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âmetro é 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 opcionais a e b, é possível 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). Esse padrão permite que MyMethod() seja compilado.

  • NÃO PERMITIDO: alterar a precisão de um valor retornado numérico

  • REQUER JULGAMENTO: uma alteração na análise de entrada e geração de novas exceções (mesmo que o comportamento de análise não seja especificado na documentação

  • DISALLOWED: Adicionar ou remover tipos de casos de uma union declaração

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

    Os testes de correspondência de padrões não são mais exaustivos depois de adicionar um tipo de caso. O compilador sinaliza expressões de correspondência de padrão como não exaustivas. Durante o tempo de execução, valores inesperados causam exceções de tempo de execução. A remoção de um tipo de caso remove a declaração de 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 lidar com a exceção. Por exemplo, no .NET Framework 4, os métodos de criação e recuperação de cultura começaram a gerar um CultureNotFoundException em vez de um ArgumentException se a cultura não pudesse ser encontrada. Como 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

    Exceções irrecuperáveis ​​não devem ser capturadas, mas precisam ser manipuladas por um manipulador de nível alto. Portanto, não se espera que os usuários tenham código que capture essas exceções explícitas. As exceções irrecuperáveis são:

  • ✔️ PERMITIDO: Lançar uma nova exceção em uma nova trajetória de código

    A exceção deve ser aplicada somente a um novo caminho de código executado com novos valores de parâmetro ou estado e que não pode ser executado pelo código existente direcionado à versão anterior.

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

    Por exemplo, um Divide método que anteriormente manipulava apenas valores positivos e lançava um ArgumentOutOfRangeException caso contrário pode ser alterado para dar suporte a valores negativos e positivos sem gerar uma exceção.

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

    Os desenvolvedores não devem confiar no texto das mensagens de erro, que também são alteradas 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: remover uma exceção em qualquer outro caso não listado acima

Atributos

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

  • Não permitido: Alterar 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 significativa.

Suporte da plataforma

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

  • NÃO PERMITIDO: não oferecer suporte ou agora exigir um pacote de serviço específico para uma operação que anteriormente tinha suporte em uma plataforma

Alterações de implementação internas

  • REQUER ANÁLISE: alterar a área de superfície de um tipo interno

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

  • REQUER ANÁLISE: alterar a implementação interna de um membro

    Essas alterações geralmente são permitidas, embora interrompa a reflexão privada. Em alguns casos, em que o código do cliente frequentemente depende de reflexão privada ou em que a alteração introduz efeitos colaterais não intencionais, essas alterações podem não ser permitidas.

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

    A capacidade de modificar o desempenho de uma operação é essencial, mas essas alterações podem interromper 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 nenhum efeito sobre outro comportamento da API em questão; caso contrário, a alteração será interruptiva.

  • ✔️ PERMITIDO: Indiretamente (e muitas vezes negativamente) alterando o desempenho de uma operação

    Se a alteração em questão não for categorizada como falha por algum outro motivo, isso será aceitável. Muitas vezes, ações precisam ser executadas que possam incluir operações extras ou que adicionem novas funcionalidades. Isso quase sempre afetará o desempenho, mas pode ser essencial para que a API em questão funcione conforme o esperado.

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

Alterações de código

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

  • NÃO PERMITIDO: Alterando um 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 gere um OverflowException e seja inaceitável.

  • NÃO PERMITIDO: remover params de um parâmetro

  • DISALLOWED: Modificação do tipo de coleção de um params parâmetro

    A partir do C# 13, params os parâmetros oferecem suporte a tipos de coleção não matriz, incluindo Span<T>, tipos de ReadOnlySpan<T> struct ou tipos de classe que implementam IEnumerable<T> com um construtor acessível sem parâmetros 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 é uma alteração de falha binária. Os chamadores compilados na versão anterior precisam ser recompilados.

  • ✔️ PERMITIDO: Convertendo um método de extensão na sintaxe do membro do bloco de extensão

    A partir do C# 14, você pode declarar membros de extensão usando extension blocos além da sintaxe de parâmetro mais antigo this. Ambos os formulários geram IL idêntico, para que os chamadores não possam distinguir entre eles. A conversão de métodos de extensão existentes para a nova sintaxe de bloco de extensão é binária e compatível com a origem.

  • NÃO PERMITIDO: alterar a ordem na qual os eventos são disparados

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

  • NÃO PERMITIDO: remover o aumento de um evento em uma determinada ação

  • NÃO PERMITIDO: Alteração do número de vezes que certos eventos são chamados

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

Consulte também