초기화된 속성 채우기
.NET 8부터 JSON이 역직렬화될 때 .NET 속성을 바꾸거나채우도록 기본 설정을 지정할 수 있습니다. JsonObjectCreationHandling 열거형은 개체 만들기 처리 선택 사항을 제공합니다.
기본(바꾸기) 동작
System.Text.Json 역직렬 변환기는 항상 대상 유형의 새 인스턴스를 만듭니다. 그러나 새 인스턴스가 만들어지더라도 일부 속성과 필드는 개체 만들기의 일부로 이미 초기화되었을 수 있습니다. 다음 형식을 고려해 보세요.
class A
{
public List<int> Numbers1 { get; } = [1, 2, 3];
public List<int> Numbers2 { get; set; } = [1, 2, 3];
}
이 클래스의 인스턴스를 만들 때 Numbers1
(및 Numbers2
) 속성 값은 세 가지 요소(1, 2, 3)가 포함된 목록입니다. JSON을 이 형식으로 역직렬화하는 경우 기본 동작은 속성 값이 바뀌는 것입니다.
Numbers1
의 경우 읽기 전용(setter 없음)이므로 목록에 여전히 값 1, 2, 3이 있습니다.- 읽기-쓰기인
Numbers2
의 경우 새 목록이 할당되고 JSON의 값이 추가됩니다.
예를 들어, 다음 역직렬화 코드를 실행하면 Numbers1
에는 값 1, 2, 3이 포함되고 Numbers2
에는 값 4, 5, 6이 포함됩니다.
A? a = JsonSerializer.Deserialize<A>("""{"Numbers1": [4,5,6], "Numbers2": [4,5,6]}""");
채우기 동작
.NET 8부터 역직렬화 동작을 변경하여 속성과 필드를 바꾸는 대신 수정(채우기)할 수 있습니다.
컬렉션형 속성의 경우 개체를 지우지 않고 재사용합니다. 컬렉션에 요소가 미리 채워져 있으면 해당 요소는 JSON의 값과 함께 역직렬화된 최종 결과에 표시됩니다. 예를 보려면 컬렉션 속성 예를 참조하세요.
속성이 있는 개체인 속성의 경우 변경 가능한 속성은 JSON 값으로 업데이트되지만 개체 참조 자체는 변경되지 않습니다.
구조체 형식 속성의 경우 변경 가능한 속성에 기존 값이 유지되고 JSON의 새 값이 추가되는 것이 효과적인 동작입니다. 그러나 참조 속성과 달리 개체 자체는 값 형식이므로 재사용되지 않습니다. 대신 구조체의 복사본이 수정된 다음 속성에 다시 할당됩니다. 예를 보려면 구조 속성 예를 참조하세요.
구조체 속성에는 setter가 있어야 합니다. 그렇지 않으면 런타임 시 InvalidOperationException이 throw됩니다.
참고 항목
현재 매개 변수가 있는 생성자가 있는 형식에서는 채우기 동작이 작동하지 않습니다. 자세한 내용은 dotnet/런타임 문제 92877를 참조하세요.
읽기 전용 속성
변경 가능한 참조 속성을 채우는 경우 속성이 참조하는 인스턴스가 바꾸기되지 않으므로 속성에 setter가 필요하지 않습니다. 이 동작은 역직렬화가 읽기 전용 속성을 채울 수도 있음을 의미합니다.
참고 항목
인스턴스가 수정된 복사본으로 바뀌므로 구조체 속성에는 여전히 setter가 필요합니다.
컬렉션 속성 예
바꾸기 동작 예에서 동일한 클래스 A
를 고려합니다. 하지만 이번에는 속성을 바꾸는 대신 채우기 속성에 대한 기본 설정으로 주석이 추가되었습니다.
[JsonObjectCreationHandling(JsonObjectCreationHandling.Populate)]
class A
{
public List<int> Numbers1 { get; } = [1, 2, 3];
public List<int> Numbers2 { get; set; } = [1, 2, 3];
}
다음 역직렬화 코드를 실행하면 Numbers1
과 Numbers2
모두 값 1, 2, 3, 4, 5, 6을 포함합니다.
A? a = JsonSerializer.Deserialize<A>("""{"Numbers1": [4,5,6], "Numbers2": [4,5,6]}""");
구조체 속성 예
다음 클래스에는 역직렬화 동작이 Populate로 설정된 구조체 속성 S1
이 포함되어 있습니다. 이 코드를 실행한 후 c.S1.Value1
의 값은 10(생성자에서)이고 c.S1.Value2
의 값은 5(JSON에서)입니다.
C? c = JsonSerializer.Deserialize<C>("""{"S1": {"Value2": 5}}""");
class C
{
public C()
{
_s1 = new S
{
Value1 = 10
};
}
private S _s1;
[JsonObjectCreationHandling(JsonObjectCreationHandling.Populate)]
public S S1
{
get { return _s1; }
set { _s1 = value; }
}
}
struct S
{
public int Value1 { get; set; }
public int Value2 { get; set; }
}
대신 기본 Replace 동작을 사용한 경우 역직렬화 후 c.S1.Value1
의 기본값은 0입니다. 이는 생성자 C()
가 호출되어 c.S1.Value1
을 10으로 설정하지만 S1의 값이 새 인스턴스로 바뀌기 때문입니다. (JSON이 기본값을 바꾸므로 c.S1.Value2
는 여전히 5입니다.)
지정 방법
바꾸기 또는 채우기에 대한 기본 설정을 지정하는 방법에는 여러 가지가 있습니다.
형식 또는 속성 수준에서 주석을 추가하려면 JsonObjectCreationHandlingAttribute 특성을 사용합니다. 형식 수준에서 특성을 설정하고 해당 Handling 속성을 Populate로 설정하면 동작은 채우기가 가능한 속성에만 적용됩니다(예: 값 형식에 setter가 있어야 함).
형식 전체 기본 설정을 Populate로 설정하고 해당 동작에서 하나 이상의 속성을 제외하려는 경우 형식 수준에서 특성을 추가한 다음 속성 수준에서 다시 추가하여 상속된 동작을 재정의할 수 있습니다. 해당 패턴은 다음 코드에 나와 있습니다.
// Type-level preference is Populate. [JsonObjectCreationHandling(JsonObjectCreationHandling.Populate)] class B { // For this property only, use Replace behavior. [JsonObjectCreationHandling(JsonObjectCreationHandling.Replace)] public List<int> Numbers1 { get; } = [1, 2, 3]; public List<int> Numbers2 { get; set; } = [1, 2, 3]; }
전역 기본 설정을 지정하려면 JsonSerializerOptions.PreferredObjectCreationHandling(또는 원본 생성의 경우 JsonSourceGenerationOptionsAttribute.PreferredObjectCreationHandling)을 설정합니다.
var options = new JsonSerializerOptions { PreferredObjectCreationHandling = JsonObjectCreationHandling.Populate };
.NET