기록 전반에 걸쳐 .NET 버전 간 및 .NET 구현 간에 높은 수준의 호환성을 유지하려고 시도했습니다. .NET 5(및 .NET Core) 이상 버전은 .NET Framework에 비해 새로운 기술로 간주될 수 있지만, 두 가지 주요 요인은 .NET Framework에서 다른 .NET 구현하는 기능을 제한합니다.
- 많은 개발자는 원래 .NET Framework 애플리케이션을 개발했거나, 계속해서 개발하고 있습니다. .NET 구현에서 일관된 동작을 기대합니다.
- .NET 표준 라이브러리 프로젝트를 통해 개발자는 .NET Framework 및 .NET 5(및 .NET Core) 이상 버전에서 공유하는 공통 API를 대상으로 하는 라이브러리를 만들 수 있습니다. 개발자는 .NET 애플리케이션에 사용되는 라이브러리가 .NET Framework 애플리케이션에서 사용되는 동일한 라이브러리와 동일하게 작동해야 한다고 예상합니다.
개발자는 .NET 구현의 호환성과 함께 지정된 .NET 구현 버전 간에 높은 수준의 호환성을 기대합니다. 특히 이전 버전의 .NET Core용으로 작성된 코드는 .NET 5 이상 버전에서 원활하게 실행되어야 합니다. 실제로 많은 개발자는 새로 릴리스된 .NET 버전에서 찾은 새 API가 해당 API가 도입된 시험판 버전과도 호환되어야 한다고 예상합니다.
이 문서에서는 호환성에 영향을 주는 변경 내용과 .NET 팀이 각 변경 유형을 평가하는 방식을 간략하게 설명합니다. .NET 팀이 가능한 호환성이 손상되는 변경에 접근하는 방식을 이해하는 것은 기존 .NET API의 동작을 수정하는 끌어오기 요청을 여는 개발자에게 특히 유용합니다.
다음 섹션에서는 .NET API에 대한 변경 내용의 범주와 애플리케이션 호환성에 미치는 영향에 대해 설명합니다. 변경은 허용(✔️), 허용되지 않음(❌) 또는 이전 동작이 얼마나 예측 가능하고 명백하며 일관된지에 대한 판단 및 평가가 ❓ 필요합니다.
비고
- 라이브러리 개발자는 .NET 라이브러리의 변경 내용을 평가하는 방법에 대한 가이드 역할을 할 뿐만 아니라 이러한 기준을 사용하여 여러 .NET 구현 및 버전을 대상으로 하는 라이브러리의 변경 내용을 평가할 수도 있습니다.
- 호환성 범주(예: 정방향 및 역방향 호환성)에 대한 자세한 내용은 코드 변경이 호환성에 영향을 줄 수 있는 방법을 참조하세요.
공개 계약에 대한 수정
이 범주의 변경 내용은 형식의 공용 노출 영역을 수정합니다. 이 범주의 변경 내용은 대부분 이전 버전과의 호환성을 위반하기 때문에 허용되지 않습니다(이전 버전의 API로 개발된 애플리케이션이 이후 버전에서 다시 컴파일하지 않고 실행할 수 있음).
유형
✔️ 허용: 인터페이스가 이미 기본 형식에 의해 구현된 경우 형식에서 인터페이스 구현 제거
❓ 판단 필요: 형식에 새 인터페이스 구현 추가
이는 기존 클라이언트에 부정적인 영향을 주지 않으므로 허용 가능한 변경입니다. 형식에 대한 모든 변경 내용은 새 구현이 허용 가능한 상태로 유지되도록 여기에 정의된 허용 가능한 변경 내용의 경계 내에서 작동해야 합니다. 디자이너 또는 직렬 변환기의 기능에 직접적인 영향을 주는 인터페이스를 추가하여 하위 수준에서 사용할 수 없는 코드 또는 데이터를 생성하는 경우 주의해야 합니다. 인터페이스를 예로 들면 다음과 같습니다 ISerializable .
❓ 판단 필요: 새 기본 클래스 도입
새 추상 멤버를 도입하거나 기존 형식의 의미 체계 또는 동작을 변경하지 않는 경우 두 기존 형식 간의 계층 구조에 형식을 도입할 수 있습니다. 예를 들어 .NET Framework 2.0에서 DbConnection 클래스는 이전에 SqlConnection 직접 파생된 Component 대한 새 기본 클래스가 되었습니다.
✔️ 허용됨: 한 어셈블리에서 다른 어셈블리로 형식 이동
이전 어셈블리는 새 어셈블리를 TypeForwardedToAttribute 가리키는 것으로 표시되어야 합니다.
✔️ 허용됨: 구조체 형식을
readonly struct형식으로 변경형식을
readonly struct형식으로struct변경할 수 없습니다.✔️ 허용됨: sealed 또는 추상 키워드를 액세스 가능한 (공개 또는 보호된) 생성자가 없는 형식에 추가
✔️ 허용됨: 형식의 가시성 확장
❌ 허용되지 않음: 형식의 네임스페이스 또는 이름 변경
❌ 허용되지 않음: 공용 형식 이름 바꾸기 또는 제거
이렇게 하면 이름이 변경되거나 제거된 형식을 사용하는 모든 코드가 중단됩니다.
비고
드문 경우에서 .NET 공용 API를 제거할 수 있습니다. 자세한 내용은 .NET의 API 제거를 참조하십시오. .NET 지원 정책에 대한 자세한 내용은 .NET 지원 정책 참조하세요.
❌ 허용 안 함: 열거형의 기본 형식 변경
이는 컴파일 시간 및 동작 호환성이 손상되는 변경뿐만 아니라 특성 인수를 분리할 수 없는 이진 호환성이 손상되는 변경입니다.
❌ 허용 안 함: 이전에 봉인되지 않았던 형식 봉인
❌ 허용 안 함: 인터페이스의 기본 형식 집합에 인터페이스 추가
인터페이스가 이전에 구현하지 않은 인터페이스를 구현하는 경우 원래 버전의 인터페이스를 구현한 모든 형식이 손상됩니다.
❓ 판단 필요: 기본 클래스의 집합에서 클래스 제거 또는 구현된 인터페이스의 집합에서 인터페이스 제거
인터페이스 제거 규칙에는 한 가지 예외가 있습니다. 제거된 인터페이스에서 파생되는 인터페이스의 구현을 추가할 수 있습니다. 예를 들어, 형식 또는 인터페이스가 이제 IDisposable을 구현하고 있는 경우 IComponent를 구현하는 IDisposable를 제거할 수 있습니다.
❌ 허용 안 함: 형식을
readonly struct구조체 형식으로 변경그러나 형식을
struct형식으로readonly struct변경할 수 있습니다.❌ 허용되지 않음: 구조체 형식을
ref struct형식으로 변경하거나 그 반대로 변경하는 것❌ 허용되지 않음: 형식의 가시성 감소
그러나 유형의 가시성을 높일 수 있습니다.
구성원
✔️ 허용됨: 가상이 아닌 멤버의 가시성 확대
✔️ 허용됨: 액세스 가능(public 또는 protected) 생성자가 없거나 형식이 봉인된 공용 형식에 추상 멤버 추가
그러나 액세스 가능(public 또는 protected) 생성자가 있는 형식이
sealed가 아닌 경우, 해당 형식에 추상 멤버를 추가할 수 없습니다.✔️ 허용됨: 형식에 액세스할 수 있는(공용 또는 보호된) 생성자가 없거나 형식이 봉인된 경우 보호된 멤버의 표시 유형 제한
✔️ 허용됨: 멤버를 제거된 형식보다 계층 구조에서 더 높은 클래스로 이동
✔️ 허용됨: 오버라이드 추가 또는 제거
재정의를 도입하면 이전 사용자가 기본을 호출할 때 재정의를 건너뛸 수 있습니다.
✔️ 허용됨: 클래스에 이전에 생성자가 없는 경우 매개 변수가 없는 생성자와 함께 클래스에 생성자 추가
그러나 매개 변수가 없는 생성자를 추가 하지 않고 이전에 생성자가 없었던 클래스에 생성자를 추가하는 것은 허용되지 않습니다.
✔️ 허용: 반환 값을
ref readonly에서ref로 변경(가상 메서드 또는 인터페이스 제외)✔️ 허용됨: 필드의 정적 형식이 변경 가능한 값 형식이 아닌 경우, 필드에서 읽기 전용 속성을 제거함
✔️ 허용됨: 이전에 정의되지 않은 새 이벤트 호출
❓ 판단 필요: 형식에 새 인스턴스 필드 추가
이 변경 사항은 직렬화에 영향을 줍니다.
❌ 허용 안 함: 공용 멤버 또는 매개 변수 이름 바꾸기 또는 제거
이렇게 하면 이름이 변경되거나 제거된 멤버 또는 매개 변수를 사용하는 모든 코드가 중단됩니다.
여기에는 속성에서 getter 또는 setter를 제거하거나 이름을 바꾸는 것뿐만 아니라 열거형 멤버의 이름을 바꾸거나 제거하는 것이 포함됩니다.
❓ 판단 필요: 인터페이스에 멤버 추가
최소 .NET 버전이 .NET Core 3.0(C# 8.0)으로 증가한다는 점에서 호환성이 손상되는 변경이긴 하나, 이는 디폴트 인터페이스 멤버(DIM)가 도입된 시기이고, 인터페이스에 정적 비추상 비가상 멤버를 추가하는 것은 허용됩니다.
구현을 제공하는 경우 기존 인터페이스에 새 멤버를 추가해도 반드시 다운스트림 어셈블리에서 컴파일 오류가 발생하는 것은 아닙니다. 그러나 모든 언어가 DIM을 지원하는 것은 아닙니다. 또한 일부 시나리오에서는 런타임에서 호출할 기본 인터페이스 멤버를 결정할 수 없습니다. C# 13
ref struct부터 형식은 인터페이스를 구현할 수 있지만, 인터페이스 형식으로 상자화하거나 변환할 수는 없습니다. 따라서 형식은ref struct모든 인스턴스 인터페이스 멤버에 대해 명시적 구현을 제공해야 하며 인터페이스에서 제공하는 기본 구현을 사용할 수 없습니다. 인터페이스ref struct에 기본 인스턴스 멤버를 추가하면ref struct에 해당 구현을 추가해야 하며, 이는 원본 코드를 깨뜨리는 변경입니다. 이러한 이유로 기존 인터페이스에 멤버를 추가할 때 판단을 사용합니다.비고
인터페이스가 형식(C# 13 이상에서 가능)으로
ref struct구현되는 경우 인터페이스에 기본 인스턴스 멤버를 추가하는 것은 해당 호출자에 대한 소스 호환성이 손상되는 변경입니다.ref struct새 멤버의 명시적 구현을 제공해야 합니다. 기본 구현으로 되돌릴 수 없습니다.❌ 허용 안 함: 공용 상수 또는 열거형 멤버의 값 변경
❌ 허용되지 않음: 속성, 필드, 매개 변수 또는 반환 값의 형식 변경
❌ 허용되지 않음: 매개 변수의 순서 추가, 제거 또는 변경
✔️ 허용됨: 매개 변수를
refref readonly로 변경매개 변수를
ref에서ref readonly로 변경하는 것은 수식을 가지는ref수정자를 사용하여 인수를 전달하는 기존 호출 사이트와 소스 호환됩니다. 이러한 호출은 변경 없이 계속 컴파일됩니다.ref를in로 변경하는 것과 달리,ref readonly매개 변수는 호출자가 rvalue(변수 아닌 값)를 자동으로 전달할 수 없습니다. 인자가 변수가 아닌 경우에는 컴파일러가 경고를 표시합니다. 기존ref통화 사이트는 유효한 상태로 유지합니다.❌ 허용 안됨:
in매개 변수를ref readonly로 변경in인수를in한정자 없이 전달하는 호출 사이트는 컴파일러에서in매개 변수를 허용할 때, 매개 변수가ref readonly으로 변경되어 참조로 전달을 요구하므로 경고를 받게 됩니다. 경고를 오류로 처리하는 호출자에게는 원본 호환성이 손상되는 변경이 발생합니다.❌ 허용 안 함: 매개 변수 이름 바꾸기(대/소문자 변경 포함)
이것은 두 가지 이유로 중단된 것으로 간주됩니다.
❌ 허용되지 않음:
ref반환 값을ref readonly반환 값으로 변경하는 것❌️ 허용되지 않음: 가상 메서드 또는 인터페이스에서
ref readonlyref반환 값으로 변경❌ 허용 안 함: 멤버에 abstract 키워드 추가 또는 제거
❌ 허용 안 함: 멤버에서 가상 키워드 제거
❌ 허용 안 함: 멤버에 가상 키워드 추가
C# 컴파일러가 가상이 아닌 메서드를 호출하는 IL(callvirt Intermediate Language) 명령을 내보내는 경향이 있기 때문에 이러한 변경은 종종 중대한 변화가 아닙니다 (
callvirt는 null 검사를 수행하나 일반 호출은 하지 않습니다.) 하지만 이러한 동작이 여러 이유로 인해 항상 동일한 것은 아닙니다.- .NET이 대상으로 하는 유일한 언어는 C#이 아닙니다.
- C# 컴파일러는 가상 메서드가 아니며, null이 아닐 가능성이 있는 경우(예: ?. null 조건부 연산자를 통해 액세스하는 메서드) 일반 호출로 최적화하려고 점차 더 많이 시도하고 있습니다.
메서드를 가상으로 만들면 소비자 코드가 비가상으로 호출하는 경우가 많습니다.
❌ 허용 안 함: 가상 멤버 추상화
가상 멤버는 파생 클래스에서 재정의할 수 있는 메서드 구현을 제공합니다. 추상 멤버는 구현을 제공하지 않으며 재정의되어야 합니다.
❌ 허용 안 함: 인터페이스 멤버에 봉인된 키워드 추가
기본 인터페이스 멤버에 추가
sealed하면 가상이 아니어 해당 멤버의 파생 형식 구현이 호출되지 않습니다.❌ 허용 안 함: 액세스 가능(public 또는 protected) 생성자가 있고 봉인되지 않은 공용 형식에 추상 멤버 추가
❌ 허용 안 함: 멤버에서 정적 키워드 추가 또는 제거
❌ 허용 안 함: 기존 오버로드를 배제하고 다른 동작을 정의하는 오버로드 추가
이렇게 하면 이전 오버로드에 바인딩된 기존 클라이언트가 중단됩니다. 예를 들어, 클래스에 UInt32를 허용하는 단일 버전의 메서드가 있는 경우, 기존 사용자는 Int32 값을 전달할 때 해당 오버로드에 성공적으로 바인딩할 수 있습니다. 그러나 Int32를 매개변수로 받는 오버로드를 추가하면, 다시 컴파일하거나 런타임에 바인딩을 사용할 때 컴파일러는 이제 새 오버로드에 바인딩됩니다. 다른 동작이 발생하는 경우 이는 호환성이 손상되는 변경일 수 있습니다.
❓ 판단 필요: 기존 오버로드에 추가 OverloadResolutionPriorityAttribute 또는 우선 순위 값 변경
OverloadResolutionPriorityAttribute 소스 레벨에서 오버로드 해석에 영향을 미칩니다. 호출자가 다시 컴파일하면 이전과 다른 오버로드로 해석될 수 있습니다. 의도된 용도는 컴파일러가 기존 오버로드보다 선호하도록 더 나은 새 오버로드에 특성을 추가하는 것입니다. 기존 오버로드에 추가하거나 이미 특성이 지정된 오버로드에서 우선 순위 값을 변경하면 다시 컴파일하는 호출자가 동작을 변경할 수 있으므로 원본 호환성이 손상되는 변경이 될 수 있습니다.
✔️ 허용됨: 제네릭 형식 매개 변수에 제약 조건 방지 추가
allows ref struct추가하면
ref struct형식을 허용하여allows ref struct형식을 형식 인수로 사용할 수 있는 범위가 확장됩니다. 형식이 아닌ref struct인수를 사용하는 기존 호출자는 영향을 받지 않습니다. 제네릭 메서드 또는 형식은 해당 형식 매개 변수의 모든 인스턴스에 대한 ref 안전 규칙을 따라야 합니다.❌ 허용 안 함: 제네릭 형식 매개 변수에서 제약 조건 방지 제거
allows ref struct제거하면
allows ref struct호출자가 형식 인수로 사용할 수 있는 형식이 제한됩니다. 형식 인수로ref struct를 전달하는 호출자는 더 이상 컴파일되지 않습니다.❌ 허용 안 함: 매개 변수가 없는 생성자를 추가하지 않고 이전에 생성자가 없었던 클래스에 생성자 추가
❌️ 허용 안 함: 필드에 읽기 전용 으로 추가
❌ 허용 안 함: 멤버의 가시성을 줄이는 것
여기에는 액세스 가능(또는
public) 생성자가 있고 형식이 봉인protected경우 보호된 멤버의 표시 여부를 줄이는 것이 포함됩니다. 그렇지 않은 경우 보호된 멤버의 가시성을 낮추는 것이 허용됩니다.멤버의 가시성을 높일 수 있습니다.
❌ 허용되지 않음: 멤버의 형식 변경
메서드의 반환 값 또는 속성 또는 필드의 형식을 수정할 수 없습니다. 예를 들어 반환 Object 하는 메서드의 시그니처는 반환 String하도록 변경할 수 없으며 그 반대의 경우도 마찬가지입니다.
❌ 허용 안 함: 비공유 필드가 없는 구조체에 인스턴스 필드 추가
구조체에 공용 필드만 있거나 필드가 전혀 없는 경우, 호출자는 모든 공용 필드를 처음 사용하기 전에 구조체에 설정하기만 하면, 구조체의 생성자를 호출하거나
default(T)로 로컬 변수를 초기화하지 않고 해당 구조체 형식의 로컬 변수를 선언할 수 있습니다. 이제 컴파일러에서 추가 필드를 초기화해야 하므로 이러한 구조체에 공용 또는 비퍼블릭이라는 새 필드를 추가하는 것은 이러한 호출자에 대한 소스 호환성이 손상되는 변경입니다.또한 필드가 없거나 공용 필드만 있는 구조체에 공개 또는 비공개 새 필드를 추가하는 것은
[SkipLocalsInit]를 코드에 적용한 호출자에 대해 이진 호환성을 깨는 변경 사항입니다. 컴파일러는 컴파일 시간에 이러한 필드를 인식하지 못했기 때문에 구조체를 완전히 초기화하지 않는 IL을 내보내 초기화되지 않은 스택 데이터에서 구조체를 만들 수 있습니다.구조체에 비공개 필드가 있는 경우, 컴파일러는 이미 생성자를 통해 초기화를 강제하며,
default(T)또는 새 인스턴스 필드를 추가하는 것은 호환성을 깨뜨리는 변경 사항이 아닙니다.❌ 허용되지 않음: 이전에 실행되지 않았을 때 기존 이벤트 발생
동작 변경
어셈블리
✔️ 허용됨: 동일한 플랫폼이 계속 지원되는 경우 어셈블리 이식 가능
❌ 허용되지 않음: 어셈블리 이름 변경
❌ 허용되지 않음: 어셈블리의 공개 키 변경
속성, 필드, 매개 변수 및 반환 값
✔️ 허용됨: 속성, 필드, 반환 값 또는 out 매개 변수의 값을 더 파생된 형식으로 변경
예를 들어, Object 형식을 반환하는 메서드는 String 인스턴스를 반환할 수 있습니다. 그러나 메서드 서명은 변경할 수 없습니다.
✔️ 허용: 멤버가 가상이 아닌 경우 속성 또는 매개 변수에 허용되는 값 범위 늘리기
메서드에 전달되거나 멤버가 반환하는 값의 범위는 확장할 수 있지만 매개 변수 또는 멤버 형식은 확장할 수 없습니다. 예를 들어 메서드에 전달된 값이 0-124에서 0-255로 확장될 수 있지만 매개 변수 형식은 변경할 ByteInt32수 없습니다.
❌ 허용 안 함: 멤버가 가상인 경우 속성 또는 매개 변수에 허용되는 값의 범위 늘리기
이 변경은 기존에 재정의된 멤버의 기능을 손상시켜서, 확장된 값 범위에 대해 정상적으로 작동하지 않게 합니다.
❌ 허용 안 함: 속성 또는 매개 변수에 허용되는 값 범위 감소
❌ 허용 안 함: 속성, 필드, 반환 값 또는 out 매개 변수에 대해 반환된 값의 범위 늘리기
❌ 허용 안 함: 속성, 필드, 메서드 반환 값 또는 out 매개 변수에 대해 반환된 값 변경
❌ 허용 안 함: 속성, 필드 또는 매개 변수의 기본값 변경
매개 변수 기본값을 변경하거나 제거하는 것은 이진 나누기가 아닙니다. 매개 변수 기본값을 제거하는 것은 원본 중단이며, 매개 변수 기본값을 변경하면 다시 컴파일한 후 동작이 중단될 수 있습니다.
이러한 이유로 매개 변수 기본값을 제거하는 것은 모호성을 제거하기 위해 해당 기본값을 새 메서드 오버로드로 "이동"하는 특정 경우에 허용됩니다. 예를 들어 기존 메서드를 고려합니다
MyMethod(int a = 1). 두 개의 선택적 매개 변수MyMethod및a가 포함된 오버로드b를 도입하는 경우,a의 기본값을 새 오버로드로 이동하여 호환성을 유지할 수 있습니다. 이제 두 오버로드는 다음과 같습니다MyMethod(int a)MyMethod(int a = 1, int b = 2). 이 패턴을 사용하면MyMethod()을(를) 컴파일할 수 있습니다.❌ 허용되지 않음: 숫자 반환 값의 정밀도 변경
❓ 판단 필요: 입력 구문 분석을 변경하고 새로운 예외를 발생시키는 경우 (설명서에 구문 분석 동작이 지정되지 않은 경우에도)
❌ 허용되지 않음:
union선언에서 유형의 추가 또는 제거형식에서
union케이스 유형을 추가하거나 제거하는 것은 이진 호환성 중단 및 소스 호환성 중단입니다.사례 유형을 추가한 후에는 패턴 일치 테스트가 더 이상 완전하지 않습니다. 컴파일러는 패턴 일치 식을 완전하지 않은 것으로 플래그 지정합니다. 런타임 시 예기치 않은 값으로 인해 런타임 예외가 발생합니다. 사례 형식을 제거하면 해당 사례 형식에 대한 생성자 선언이 제거됩니다.
예외
✔️ 허용됨: 기존 예외보다 더 파생된 예외를 던지기
새 예외는 기존 예외의 하위 클래스이므로 이전 예외 처리 코드는 예외를 계속 처리합니다. 예를 들어 .NET Framework 4에서 문화권 생성 및 검색 메서드는 문화권을 찾을 수 없는 경우 CultureNotFoundException 대신 ArgumentException throw하기 시작했습니다. CultureNotFoundException이(가) ArgumentException에서 파생되었기 때문에, 이는 허용 가능한 변경입니다.
✔️ 허용됨: NotSupportedException, NotImplementedException, NullReferenceException보다 더 구체적인 예외를 throw합니다.
✔️ 허용됨: 복구할 수 없는 것으로 간주되는 예외를 던지는 것
복구 불가능한 예외는 catch하지 말고 포괄적인 상위 처리기에서 처리해야 합니다. 따라서 사용자에게는 이러한 명시적 예외를 catch하는 코드가 없을 것으로 예상됩니다. 복구할 수 없는 예외는 다음과 같습니다.
✔️ 허용됨: 새로운 코드 경로에서 새 예외를 던집니다
예외는 새 매개 변수 값 또는 상태로 실행되고 이전 버전을 대상으로 하는 기존 코드에서 실행할 수 없는 새 코드 경로에만 적용되어야 합니다.
✔️ 허용됨: 더 강력한 동작 또는 새 시나리오를 사용하도록 예외 제거
예를 들어, 이전에 양수 값만 처리하고, 그렇지 않은 경우에는 예외를 발생시키던
Divide메서드를 음수 값과 양수 값을 모두 지원하도록 변경할 수 있습니다. 이 경우 예외는 발생하지 않습니다.✔️ 허용: 오류 메시지의 텍스트 변경
개발자는 사용자의 문화권에 따라 변경되는 오류 메시지의 텍스트에 의존해서는 안 됩니다.
❌ 허용 안 함: 위에 나열되지 않은 다른 경우에 예외를 던지기
❌ 허용 안 함: 위에 나열되지 않은 다른 경우에 예외 제거
특성
✔️ 허용: 관찰할 수 없는 특성 값 변경
❌ 허용 안 함 : 관찰 가능한 특성 값 변경
❓ 판단 필요: 특성 제거
대부분의 경우 특성(예: NonSerializedAttribute)을 제거하는 것은 호환성이 손상되는 변경입니다.
플랫폼 지원
✔️ 허용됨: 이전에 지원되지 않았던 플랫폼에서 작업 지원
❌ 허용되지 않음: 플랫폼에서 이전에 지원되었던 작업에 대해 특정 서비스 팩을 더 이상 지원하지 않거나 지금은 요구함
내부 구현 변경 내용
❓ 판단 필요: 내부 유형의 표면적 변경
이러한 변경 내용은 일반적으로 허용되지만 개인 리플렉션을 중단합니다. 인기 있는 타사 라이브러리 또는 많은 수의 개발자가 내부 API에 의존하는 경우 이러한 변경이 허용되지 않을 수 있습니다.
❓ 판단 필요: 멤버의 내부 구현 변경
일반적으로 이러한 변경 내용은 개인 리플렉션을 중단하지만 허용됩니다. 고객 코드가 개인 리플렉션에 자주 의존하거나 변경으로 의도하지 않은 부작용이 발생하는 경우 이러한 변경이 허용되지 않을 수 있습니다.
✔️ 허용됨: 작업의 성능 향상
작업의 성능을 수정하는 기능은 필수이지만 이러한 변경으로 작업의 현재 속도에 의존하는 코드가 손상될 수 있습니다. 비동기 작업의 타이밍에 따라 달라지는 코드의 경우 특히 그렇습니다. 성능 변경은 문제의 API의 다른 동작에 영향을 주지 않아야 합니다. 그렇지 않으면 변경 내용이 중단됩니다.
✔️ 허용됨: 간접적으로(그리고 종종 부정적인) 작업 성능 변경
문제의 변경 내용이 다른 이유로 인해 호환성이 손상되는 것으로 분류되지 않는 경우 이는 허용됩니다. 추가 작업을 포함하거나 새 기능을 추가하는 작업을 수행해야 하는 경우가 많습니다. 이는 거의 항상 성능에 영향을 주지만 문제의 API가 예상대로 작동하도록 하는 데 필수적일 수 있습니다.
❌ 허용되지 않음: 동기 API를 비동기로 변경(또는 그 반대)
코드 변경
✔️ 허용됨: 매개 변수 설정에 params 추가
❌ 허용 안 함: 코드 블록에 확인된 문 추가
이 변경으로 인해 이전에 실행한 코드가 throw OverflowException 되고 허용되지 않을 수 있습니다.
❌ 허용 안 함: 매개 변수에서 매개 변수 제거
❌ 허용 안 함: 매개 변수의
params컬렉션 형식 변경C# 13부터
params매개 변수는 배열이 아닌 컬렉션 형식을 지원하며, 여기에는 매개 변수 없는 접근 가능한 생성자와 인스턴스 Span<T> 메서드를 가진 ReadOnlySpan<T> 구조체 또는 클래스 형식, IEnumerable<T>으로 구현된 특정 인터페이스 형식 예를 들어Add등이 포함됩니다. 기존params매개 변수의 컬렉션 유형을 변경하면(예를 들어,params T[]에서params ReadOnlySpan<T>로 변경) 메서드의 IL 서명이 변경되며, 이는 바이너리 비호환성을 초래합니다. 이전 버전에서 컴파일된 호출자는 반드시 다시 컴파일해야 합니다.✔️ 허용: 확장 메서드를 확장 블록 멤버 구문으로 변환
C# 14부터 이전
extension-매개 변수 구문 외에도 블록을 사용하여this확장 멤버를 선언할 수 있습니다. 두 양식 모두 동일한 IL을 생성하므로 호출자는 둘을 구분할 수 없습니다. 기존 확장 메서드를 새 확장 블록 구문으로 변환하는 것은 이진이며 원본과 호환됩니다.❌ 허용되지 않음: 이벤트가 발생하는 순서 변경
개발자는 이벤트가 동일한 순서로 실행되기를 합리적으로 예상할 수 있으며 개발자 코드는 이벤트가 발생하는 순서에 따라 자주 달라집니다.
❌ 허용되지 않음: 지정된 작업에서 이벤트 발생 제거
❌ 허용 안 함: 지정된 이벤트가 호출되는 횟수 변경
❌ 허용 안 함: FlagsAttribute을(를) 열거형에 추가
참고하십시오
.NET