Compartilhar via


Considerações sobre versão e atualização para desenvolvedores do C#

A compatibilidade é uma meta importante, pois novos recursos são adicionados à linguagem C#. Em quase todos os casos, o código existente pode ser recompilado com uma nova versão do compilador sem nenhum problema. A equipe de runtime do .NET também tem uma meta para garantir a compatibilidade para bibliotecas atualizadas. Em quase todos os casos, quando seu aplicativo é iniciado a partir de um runtime atualizado com bibliotecas atualizadas, o comportamento é exatamente o mesmo das versões anteriores.

A versão de linguagem usada para compilar seu aplicativo normalmente corresponde ao moniker da estrutura de destino de runtime (TFM) referenciado em seu projeto. Para obter mais informações sobre como alterar a versão do idioma padrão, consulte o artigo intitulado configurar sua versão do idioma. Esse comportamento padrão garante a compatibilidade máxima.

Quando alterações interruptivas são introduzidas, elas são classificadas como:

  • Alteração de falha binária: uma alteração de falha binária causa um comportamento diferente, incluindo possivelmente falha, em seu aplicativo ou biblioteca quando iniciada usando um novo runtime. Você deve recompilar seu aplicativo para incorporar essas alterações. O binário existente não funcionará corretamente.
  • Alteração de falha de origem: uma alteração de falha de origem altera o significado do código-fonte. Você precisa fazer edições de código-fonte antes de compilar seu aplicativo com a versão mais recente do idioma. O binário existente será executado corretamente com o host e o runtime mais recentes. Observe que, para a sintaxe da linguagem, uma alteração de falha de origem também é uma alteração comportamental, conforme definido nas alterações de interrupção do runtime.

Quando uma alteração de falha binária afeta seu aplicativo, você deve recompilar seu aplicativo, mas não precisa editar nenhum código-fonte. Quando uma alteração de falha de origem afeta seu aplicativo, o binário existente ainda é executado corretamente em ambientes com o runtime e as bibliotecas atualizados. No entanto, você deve fazer alterações de origem para recompilar com a nova versão do idioma e o runtime. Se uma alteração for a quebra de origem e a quebra binária, você deverá recompilar seu aplicativo com a versão mais recente e fazer atualizações de origem.

Devido ao objetivo de evitar alterações interruptivas da equipe de linguagem C# e da equipe de runtime, atualizar seu aplicativo normalmente é uma questão de atualizar o TFM e recompilar o aplicativo. No entanto, para bibliotecas distribuídas publicamente, você deve avaliar cuidadosamente sua política para TFMs com suporte e versões de linguagem com suporte. Você pode estar criando uma nova biblioteca com recursos encontrados na versão mais recente e precisa garantir que os aplicativos criados usando versões anteriores do compilador possam usá-la. Ou você pode estar atualizando uma biblioteca existente e muitos de seus usuários talvez ainda não tenham atualizado as versões.

Apresentando alterações interruptivas em suas bibliotecas

Ao adotar novos recursos de linguagem na API pública da biblioteca, você deverá avaliar se a adoção do recurso apresenta uma alteração binária ou de falha de origem para os usuários da biblioteca. Todas as alterações na implementação interna que não aparecem nas public interfaces ou nas protected interfaces são compatíveis.

Observação

Se você usar os System.Runtime.CompilerServices.InternalsVisibleToAttribute tipos para habilitar a visualização de membros internos, os membros internos poderão introduzir alterações significativas.

Uma alteração de falha binária exige que os usuários recompilem o código para usar a nova versão. Por exemplo, considere este método público:

public double CalculateSquare(double value) => value * value;

Se você adicionar o in modificador ao método, essa será uma alteração de falha binária:

public double CalculateSquare(in double value) => value * value;

Os usuários devem recompilar qualquer aplicativo que use o CalculateSquare método para que a nova biblioteca funcione corretamente.

Uma alteração de falha de origem exige que os usuários alterem o código antes de recompilarem. Por exemplo, considere este tipo:

public class Person
{
    public string FirstName { get; }
    public string LastName { get; }

    public Person(string firstName, string lastName) => (FirstName, LastName) = (firstName, lastName);

    // other details omitted
}

Em uma versão mais recente, você gostaria de aproveitar os membros sintetizados gerados para record tipos. Você faz a seguinte alteração:

public record class Person(string FirstName, string LastName);

A alteração anterior requer alterações para qualquer tipo derivado de Person. Todas essas declarações devem adicionar o record modificador às suas declarações.

Impacto das alterações interruptivas

Ao adicionar uma alteração de falha binária à biblioteca, você força todos os projetos que usam sua biblioteca a recompilar. No entanto, nenhum código-fonte nesses projetos precisa ser alterado. Como resultado, o impacto da alteração significativa é razoavelmente pequeno para cada projeto.

Ao fazer uma alteração de falha de origem em sua biblioteca, você exige que todos os projetos façam alterações de origem para usar sua nova biblioteca. Se a alteração necessária exigir novos recursos de linguagem, você força esses projetos a atualizar para a mesma versão de idioma e TFM que você está usando agora. Você exigiu mais trabalho para seus usuários e, possivelmente, forçou-os a atualizar também.

O impacto de qualquer alteração significativa que você fizer depende do número de projetos que têm uma dependência em sua biblioteca. Se sua biblioteca for usada internamente por alguns aplicativos, você poderá reagir a quaisquer alterações significativas em todos os projetos afetados. No entanto, se sua biblioteca for baixada publicamente, você deverá avaliar o impacto potencial e considerar alternativas:

  • Você pode adicionar novas APIs que apis paralelas existentes.
  • Você pode considerar builds paralelos para TFMs diferentes.
  • Você pode considerar a segmentação múltipla.