메모
이 문서는 기능 사양입니다. 사양은 기능의 디자인 문서 역할을 합니다. 여기에는 기능 디자인 및 개발 중에 필요한 정보와 함께 제안된 사양 변경 내용이 포함됩니다. 이러한 문서는 제안된 사양 변경이 완료되고 현재 ECMA 사양에 통합될 때까지 게시됩니다.
기능 사양과 완료된 구현 간에 약간의 불일치가 있을 수 있습니다. 이러한 차이는 관련LDM(언어 디자인 모임) 노트에서 캡처됩니다.
사양문서에서 기능 스펙렛을 C# 언어 표준으로 채택하는 프로세스에 대해 자세히 알아볼 수 있습니다.
챔피언 이슈: https://github.com/dotnet/csharplang/issues/6420
문법
property_declaration 문법 (§14.7.1) 다음과 같이 업데이트됩니다.
property_declaration
- : attributes? property_modifier* type member_name property_body
+ : attributes? property_modifier* 'partial'? type member_name property_body
;
주의: 이는 method_header(§15.6.1) 및 class_declaration(§15.2.1) 지정 방식과 약간 유사합니다. (문제 #946 주문 요구 사항을 완화할 것을 제안하며 partial
한정자를 허용하는 모든 선언에 적용될 수 있습니다. 가까운 장래에 이러한 순서 완화를 지정하고 이 기능이 구현된 것과 동일한 릴리스에서 구현하려고 합니다.)
선언 정의 및 구현
속성 선언에 부분 한정자가 포함된 경우 해당 속성은 부분 속성이라고 불립니다. 부분적인 속성은 부분적인 형식의 멤버로만 선언할 수 있습니다.
부분 속성 선언은 접근자에 모두 세미콜론 본문이 있고 extern
한정자가 없는 경우 선언을 정의하는 있다고 합니다. 그렇지 않으면, 는을 구현하는 선언입니다.
partial class C
{
// Defining declaration
public partial string Prop { get; set; }
// Implementing declaration
public partial string Prop { get => field; set => field = value; }
}
세미콜론 접근자 본문이 있는 구문 형식을 정의 선언에 예약했기 때문에, 부분 속성은 자동으로 구현될 수없습니다. 따라서 자동으로 구현된 속성(§15.7.4)을 다음과 같이 조정합니다.
자동으로 구현된 속성(또는 짧게는 자동 속성)은 세미콜론 전용 접근자 본문이 있는 비 추상적, 비-extern, 부분적이지 않은 참조되지 않은 속성입니다.
설명. 컴파일러가 격리된 단일 선언을 보고 정의 또는 구현 선언인지 여부를 알 수 있는 것이 유용합니다. 예를 들어, 동일한 partial
속성 선언 두 개를 포함하는 방법으로 자동 속성을 허용하고 싶지 않습니다. 이 기능의 사용 사례는 자동 속성을 사용하여 partial 속성을 구현하는 것과 관련이 있다고 생각하지 않지만 간단한 구현이 필요한 경우 field
키워드를 사용하면 작업을 충분히 간단하게 만들 수 있다고 생각합니다.
partial 속성에는 선언 정의하는 하나와 선언 구현하는하나가 있어야 합니다.
설명. 또한 선언을 두 개 이상의 부분으로 분할하여 여러 위치에서 다른 접근자를 구현할 수 있도록 하는 것이 유용하지 않다고 생각합니다. 따라서 부분 메서드에 의해 설정된 체계를 모방하기만 하면 됩니다.
partial 속성의 정의 선언만 탐색에 참여하며, 부분 메서드의 정의 선언만 오버로드 해결에 참여하는 방식과 유사합니다.
설명. 컴파일러에서는 정의 선언의 기호만 멤버 목록에 표시되고 구현 파트의 기호는 정의 기호를 통해 액세스할 수 있습니다. 그러나 nullable 분석과 같은 일부 기능은 더 유용한 동작을 제공하기 위해 구현 선언에 대한 내용을 쉽게 파악할 수 있습니다.
partial class C
{
public partial string Prop { get; set; }
public partial string Prop { get => field; set => field = value; }
public C() // warning CS8618: Non-nullable property 'Prop' must contain a non-null value when exiting constructor. Consider declaring the property as nullable.
{
}
}
부분 속성은 abstract
한정자를 가질 수 없습니다.
partial 속성은 인터페이스 속성을 명시적으로 구현할 수 없습니다.
특성 병합
부분 메서드와 마찬가지로 결과 속성의 특성은 부분의 결합된 특성이 지정되지 않은 순서로 연결되고 중복은 제거되지 않습니다.
호출자 정보 특성
저희는 표준에서 다음 규정을 조정합니다.
부분
메서드멤버 선언의 일부를 정의하고 구현하는 매개 변수에 동일한 호출자 정보 특성을 갖는 것은 오류입니다. 정의 파트의 호출자 정보 특성만 적용되는 반면 구현 파트에서만 발생하는 호출자 정보 특성은 무시됩니다.
- 설명된 오류는
AllowMultiple = true
없는 이러한 특성의 정의에서 제외됩니다. 부분 선언을 포함하여 여러 번 사용하면 오류가 발생합니다. - 부분 메서드의 구현 부분에 있는 매개 변수에 호출자 정보 특성이 적용되면 Roslyn 컴파일러는 경고를 보고합니다. 부분 속성에서 동일한 시나리오에 대한 경고도 보고합니다.
일치하는 서명
2020년 9월 14일 LDM 회의에서는 경고 물결에 도입된 부분 메서드의 서명 일치에 대한 "엄격한" 요구 사항 집합을 정의했습니다. 부분 속성은 서명 일치를 위한 부분 메서드와 유사한 요구 사항이 있되, 불일치에 대한 모든 진단이 기본적으로 보고되고 경고 웨이브 뒤에 보관되지 않는다는 점이 예외입니다.
서명 일치 요구 사항은 다음과 같습니다.
- 런타임에 중요한 부분 속성 선언 간의 형식 및 ref 종류 차이로 인해 컴파일 시간 오류가 발생합니다.
- 부분 속성 선언에서 튜플 요소 이름이 다르면 부분 메서드와 마찬가지로 컴파일 시간 오류가 발생합니다.
- 속성 선언과 해당 접근자 선언에는 동일한 한정자가 있어야 하지만 한정자는 다른 순서로 나타날 수 있습니다.
- 이 예외는 선언 을(를) 구현하는에만 나타날 수 있는
extern
한정자에는 해당되지 않습니다.
- 이 예외는 선언 을(를) 구현하는에만 나타날 수 있는
- 부분 속성 선언의 서명에 있는 다른 모든 구문 차이는 다음 예외를 제외하고 컴파일 시간 경고가 발생합니다.
- 부분 속성 선언 또는 부분 속성 선언 내의 특성 목록은 일치시킬 필요가 없습니다. 대신 해당 위치의 특성 병합은 특성 병합따라 수행됩니다.
- Nullable 컨텍스트 차이로 인해 경고가 발생하지 않습니다. 즉, 형식 중 하나가 nullable-oblivious이고 다른 형식이 nullable 주석이 있거나 nullable이 아닌 주석이 있는 경우의 차이로 인해 경고가 발생하지 않습니다.
- 기본 매개 변수 값은 일치시킬 필요가 없습니다. 부분 인덱서의 구현 부분에 기본 매개 변수 값이 있는 경우 경고가 보고됩니다. 부분 메서드의 구현 부분에 기본 매개 변수 값이 있는 경우 발생하는 기존 경고와 유사합니다.
- 선언 정의 및 구현에서 매개 변수 이름이 다를 때 경고가 발생합니다. 정의 부분의 매개 변수 이름은 사용 사이트 및 내보내기에서 사용됩니다.
- "명시되지 않은 null 허용 여부와 관련되지 않은 null 허용 여부의 차이로 인해 경고가 발생합니다." 접근자 본문을 분석할 때 구현 파트 서명이 사용됩니다. 정의 파트 서명은 사용 사이트를 분석하고 내보내는 데 사용됩니다. 이는 부분 메서드와 일치합니다.
partial class C1
{
public partial string Prop { get; private set; }
// Error: accessor modifier mismatch in 'set' accessor of 'Prop'
public partial string Prop { get => field; set => field = value; }
}
partial class C2
{
public partial string Prop { get; init; }
// Error: implementation of 'Prop' must have an 'init' accessor to match definition
public partial string Prop { get => field; set => field = value; }
}
partial class C3
{
public partial string Prop { get; }
// Error: implementation of 'Prop' cannot have a 'set' accessor because the definition does not have a 'set' accessor.
public partial string Prop { get => field; set => field = value; }
}
partial class C4
{
public partial string this[string s = "a"] { get; set; }
public partial string this[string s] { get => s; set { } } // ok
public partial string this[int i, string s = "a"] { get; set; }
public partial string this[int i, string s = "a"] { get => s; set { } } // CS1066: The default value specified for parameter 's' will have no effect because it applies to a member that is used in contexts that do not allow optional arguments
}
설명서 주석
부분 속성에 대한 문서 주석의 동작이 부분 메서드에 대해 제공된 동작과 일치하도록 합니다. 해당 동작은 https://github.com/dotnet/csharplang/issues/5193자세히 설명되어 있습니다.
부분 속성의 정의 또는 구현 부분에 문서 주석을 포함할 수 있습니다. (문서 주석은 속성 접근자에서 지원되지 않습니다.)
문서 주석이 속성의 일부 중 하나에만 있는 경우 해당 문서 주석은 정상적으로 사용됩니다(ISymbol.GetDocumentationCommentXml()
통해 표시되고 설명서 XML 파일에 기록됨).
두 부분 모두에 문서 주석이 있으면 정의 부분에 대한 모든 문서 주석이 삭제되고 구현 부분에 대한 문서 주석만 사용됩니다.
예를 들어 다음 프로그램은 다음과 같습니다.
/// <summary>
/// My type
/// </summary>
partial class C
{
/// <summary>Definition part comment</summary>
/// <returns>Return value comment</returns>
public partial int Prop { get; set; }
/// <summary>Implementation part comment</summary>
public partial int Prop { get => 1; set { } }
}
결과는 다음 XML 설명서 파일입니다.
<?xml version="1.0"?>
<doc>
<assembly>
<name>ConsoleApp1</name>
</assembly>
<members>
<member name="T:C">
<summary>
My type
</summary>
</member>
<member name="P:C.Prop">
<summary>
Implementation part comment
</summary>
</member>
</members>
</doc>
매개 변수 이름이 부분 선언 간에 다른 경우 <paramref>
요소는 소스 코드의 설명서 주석과 연결된 선언의 매개 변수 이름을 사용합니다. 예를 들어 구현 선언에 배치된 문서 주석의 paramref는 해당 매개 변수 이름을 사용하여 구현 선언의 매개 변수 기호를 참조합니다. 이는 부분 메서드와 일치합니다.
/// <summary>
/// My type
/// </summary>
partial class C
{
public partial int this[int x] { get; set; }
/// <summary>
/// <paramref name="x"/> // warning CS1734: XML comment on 'C.this[int]' has a paramref tag for 'x', but there is no parameter by that name
/// <paramref name="y"/> // ok. 'Go To Definition' will go to 'int y'.
/// </summary>
public partial int this[int y] { get => 1; set { } } // warning CS9256: Partial property declarations 'int C.this[int x]' and 'int C.this[int y]' have signature differences.
}
결과는 다음 XML 설명서 파일입니다.
<?xml version="1.0"?>
<doc>
<assembly>
<name>ConsoleApp1</name>
</assembly>
<members>
<member name="T:C">
<summary>
My type
</summary>
</member>
<member name="P:C.Item(System.Int32)">
<summary>
<paramref name="x"/> // warning CS1734: XML comment on 'C.this[int]' has a paramref tag for 'x', but there is no parameter by that name
<paramref name="y"/> // ok. 'Go To Definition' will go to 'int y'.
</summary>
</member>
</members>
</doc>
메타데이터 서명은 정의 부분의 매개 변수 이름을 사용하기 때문에 혼동될 수 있습니다. 이러한 혼동을 방지하기 위해 매개 변수 이름이 여러 부분에서 일치하는지 확인하는 것이 좋습니다.
인덱서
2022년 11월 2일에LDM 모임에 따라 이 기능을 통해 인덱서가 지원됩니다.
인덱서 문법은 다음과 같이 수정됩니다.
indexer_declaration
- : attributes? indexer_modifier* indexer_declarator indexer_body
+ : attributes? indexer_modifier* 'partial'? indexer_declarator indexer_body
- | attributes? indexer_modifier* ref_kind indexer_declarator ref_indexer_body
+ | attributes? indexer_modifier* 'partial'? ref_kind indexer_declarator ref_indexer_body
;
부분 인덱서 매개변수는 일치 서명에서와 같은 규칙에 따라 선언 간에 일치해야 합니다. 특성 병합 부분 인덱서 매개 변수에서 수행됩니다.
partial class C
{
public partial int this[int x] { get; set; }
public partial int this[int x]
{
get => this._store[x];
set => this._store[x] = value;
}
}
// attribute merging
partial class C
{
public partial int this[[Attr1] int x]
{
[Attr2] get;
set;
}
public partial int this[[Attr3] int x]
{
get => this._store[x];
[Attr4] set => this._store[x] = value;
}
// results in a merged member emitted to metadata:
public int this[[Attr1, Attr3] int x]
{
[Attr2] get => this._store[x];
[Attr4] set => this._store[x] = value;
}
}
열려 있는 문제
다른 멤버 종류
한 커뮤니티 구성원이 부분 이벤트에 대한 지원을 요청하는 토론을 열었습니다. 2022년 11월 2일 LDM 회의에서 우리는 당시 아무도 요청하지 않았기 때문에 이벤트에 대한 지원을 연기하기로 결정했습니다. 이 요청이 제출되었으므로 마지막 논의로부터 1년이 지난 지금, 이 질문을 다시 검토해야 할 수도 있습니다.
또한 생성자, 연산자, 필드 등의 부분 선언을 허용하는 데 더 많은 작업을 수행할 수 있지만, 이미 부분 속성을 수행하고 있기 때문에 이러한 디자인 부담이 정당화되는지는 불분명합니다.
C# feature specifications