Соображения относительно версии и обновления для разработчиков на C#

Совместимость является важной целью, так как новые функции добавляются на язык C#. В большинстве случаев существующий код сможет компилироваться в новой версии компилятора безо всяких проблем. Команда среды выполнения .NET также имеет цель обеспечить совместимость обновленных библиотек. В почти всех случаях, когда приложение запускается из обновленной среды выполнения с обновленными библиотеками, поведение точно совпадает с предыдущими версиями.

Языковая версия, используемая для компиляции приложения, обычно соответствует моникеру целевой платформы среды выполнения (TFM), на которую ссылается ваш проект. Дополнительные сведения об изменении языковой версии по умолчанию см. в статье, описанной в статье о настройке версии языка. Это поведение по умолчанию обеспечивает максимальную совместимость.

При появлении критических изменений они классифицируются как:

  • Двоичное критическое изменение: двоичное критическое изменение вызывает другое поведение, в том числе, возможно, сбой в приложении или библиотеке при запуске с помощью новой среды выполнения. Чтобы включить эти изменения, необходимо перекомпилировать приложение. Существующий двоичный файл не будет работать правильно.
  • Критическое изменение источника: критическое изменение источника изменяет смысл исходного кода. Перед компиляцией приложения с последней версией языка необходимо внести изменения в исходный код. Существующий двоичный файл будет работать правильно с новым узлом и средой выполнения. Обратите внимание, что для синтаксиса языка критическое изменение источника также является изменением поведения, как определено в критических изменениях среды выполнения.

Если двоичное критическое изменение влияет на приложение, необходимо перекомпилировать приложение, но вам не нужно изменять исходный код. Когда критическое изменение источника влияет на приложение, существующий двоичный файл по-прежнему работает правильно в средах с обновленной средой выполнения и библиотеками. Однако необходимо внести изменения в источник для повторной компиляции с новой языковой версией и средой выполнения. Если изменение является критическим и двоичным, необходимо перекомпилировать приложение с последней версией и внести обновления источника.

Из-за цели избежать критических изменений командой языка C# и командой среды выполнения обновление приложения обычно является вопросом обновления TFM и перестроения приложения. Однако для библиотек, распределенных публично, следует тщательно оценить политику для поддерживаемых TFM и поддерживаемых языковых версий. Например, если вы создаете новую библиотеку с функциями из последней версии, но ее должны использовать приложения, созданные в предыдущих версиях компилятора. Или вы можете обновить существующую библиотеку и многие пользователи, возможно, еще не обновили версии.

Введение критических изменений в библиотеки

При внедрении новых языковых функций в общедоступном API библиотеки следует оценить, вводит ли функция двоичное или исходное критическое изменение для пользователей библиотеки. Все изменения внутренней реализации, которые не отображаются в public интерфейсах или protected не совместимы.

Примечание.

Если вы используете System.Runtime.CompilerServices.InternalsVisibleToAttribute для включения типов для просмотра внутренних элементов, внутренние члены могут вносить критические изменения.

Двоичное критическое изменение требует, чтобы пользователи перекомпилировать свой код, чтобы использовать новую версию. Например, рассмотрим этот общедоступный метод:

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

Если добавить in модификатор в метод, это двоичное критическое изменение:

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

Пользователи должны перекомпилировать любое приложение, использующее CalculateSquare метод для правильной работы новой библиотеки.

Критическое изменение источника требует, чтобы пользователи изменили свой код перед повторной компиляцией. Например, рассмотрим этот тип:

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

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

    // other details omitted
}

В более новой версии вы хотите воспользоваться преимуществами синтезированных элементов, созданных для record типов. Вы вносите следующее изменение:

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

Для предыдущего изменения требуются изменения любого типа, производных от Person. Все эти объявления должны добавить record модификатор в их объявления.

Влияние критических изменений

При добавлении двоичного критического изменения в библиотеку вы принудительно принудительно перекомпилируйте все проекты, использующие библиотеку. Однако ни один исходный код в этих проектах не должен меняться. В результате влияние критического изменения достаточно мало для каждого проекта.

При внесении критического изменения в библиотеку для всех проектов необходимо внести изменения в источник, чтобы использовать новую библиотеку. Если для изменения требуются новые языковые функции, вы принудительно выполните обновление этих проектов до той же языковой версии и TFM, которую вы используете. Вам потребуется больше работы для пользователей, и, возможно, заставили их обновить.

Влияние любых критических изменений зависит от количества проектов, имеющих зависимость от библиотеки. Если библиотека используется внутри нескольких приложений, вы можете реагировать на любые критические изменения во всех затронутых проектах. Однако если библиотека загружена публично, следует оценить потенциальное влияние и рассмотреть альтернативные варианты:

  • Вы можете добавить новые API, которые параллелит существующие API.
  • Вы можете рассмотреть параллельные сборки для разных TFM.
  • Вы можете рассмотреть возможность многонацеливания.