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에 대한 병렬 빌드를 고려할 수 있습니다.
  • 멀티 대상 지정을 고려해 볼 수도 있습니다.