변경할 수 없는 형식 및 속성 사용
변경할 수 없는 형식 인스턴스화된 후 개체의 속성 또는 필드 값을 변경하지 못하게 하는 형식입니다. 형식은 레코드일 수 있으며, 공용 속성이나 필드가 없을 수도 있고, 읽기 전용 속성이 있을 수도 있으며, private 또는 초기화 용도로만 설정할 수 있는 setter가 있는 속성이 있을 수 있습니다. System.String 변경할 수 없는 형식의 예입니다. System.Text.Json 변경할 수 없는 형식으로 JSON을 역직렬화할 수 있는 다양한 방법을 제공합니다.
매개 변수가 있는 생성자
기본적으로 System.Text.Json
기본 공용 매개 변수 없는 생성자를 사용합니다. 그러나 매개 변수가 있는 생성자를 사용하도록 지시할 수 있으므로 변경할 수 없는 클래스 또는 구조체를 역직렬화할 수 있습니다.
클래스의 경우 매개 변수가 있는 생성자만 있으면 해당 생성자가 사용됩니다.
구조체 또는 여러 생성자가 있는 클래스의 경우 [JsonConstructor] 특성을 적용하여 사용할 클래스를 지정합니다. 특성을 사용하지 않으면 공용 매개 변수가 없는 생성자가 항상 사용됩니다( 있는 경우).
다음 예제에서는
[JsonConstructor]
특성을 사용합니다.using System.Text.Json; using System.Text.Json.Serialization; namespace ImmutableTypes { public struct Forecast { public DateTime Date { get; } public int TemperatureC { get; } public string Summary { get; } [JsonConstructor] public Forecast(DateTime date, int temperatureC, string summary) => (Date, TemperatureC, Summary) = (date, temperatureC, summary); } public class Program { public static void Main() { string json = """ { "date":"2020-09-06T11:31:01.923395-07:00", "temperatureC":-1, "summary":"Cold" } """; Console.WriteLine($"Input JSON: {json}"); var options = JsonSerializerOptions.Web; Forecast forecast = JsonSerializer.Deserialize<Forecast>(json, options); Console.WriteLine($"forecast.Date: {forecast.Date}"); Console.WriteLine($"forecast.TemperatureC: {forecast.TemperatureC}"); Console.WriteLine($"forecast.Summary: {forecast.Summary}"); string roundTrippedJson = JsonSerializer.Serialize<Forecast>(forecast, options); Console.WriteLine($"Output JSON: {roundTrippedJson}"); } } } // Produces output like the following example: // //Input JSON: { "date":"2020-09-06T11:31:01.923395-07:00","temperatureC":-1,"summary":"Cold"} //forecast.Date: 9 / 6 / 2020 11:31:01 AM //forecast.TemperatureC: -1 //forecast.Summary: Cold //Output JSON: { "date":"2020-09-06T11:31:01.923395-07:00","temperatureC":-1,"summary":"Cold"}
Imports System.Text.Json Imports System.Text.Json.Serialization Namespace ImmutableTypes Public Structure Forecast Public ReadOnly Property [Date] As Date Public ReadOnly Property TemperatureC As Integer Public ReadOnly Property Summary As String <JsonConstructor> Public Sub New([Date] As Date, TemperatureC As Integer, Summary As String) Me.Date = [Date] Me.TemperatureC = TemperatureC Me.Summary = Summary End Sub End Structure Public NotInheritable Class Program Public Shared Sub Main() Dim json As String = "{""date"":""2020-09-06T11:31:01.923395-07:00"",""temperatureC"":-1,""summary"":""Cold""}" Console.WriteLine($"Input JSON: {json}") Dim forecast1 As Forecast = JsonSerializer.Deserialize(Of Forecast)(json, JsonSerializerOptions.Web) Console.WriteLine($"forecast.Date: {forecast1.[Date]}") Console.WriteLine($"forecast.TemperatureC: {forecast1.TemperatureC}") Console.WriteLine($"forecast.Summary: {forecast1.Summary}") Dim roundTrippedJson As String = JsonSerializer.Serialize(forecast1, JsonSerializerOptions.Web) Console.WriteLine($"Output JSON: {roundTrippedJson}") End Sub End Class End Namespace ' Produces output like the following example: ' 'Input JSON: { "date":"2020-09-06T11:31:01.923395-07:00","temperatureC":-1,"summary":"Cold"} 'forecast.Date: 9 / 6 / 2020 11:31:01 AM 'forecast.TemperatureC: -1 'forecast.Summary: Cold 'Output JSON: { "date":"2020-09-06T11:31:01.923395-07:00","temperatureC":-1,"summary":"Cold"}
.NET 7 및 이전 버전에서
[JsonConstructor]
특성은 공용 생성자와만 사용할 수 있습니다.
매개 변수가 있는 생성자의 매개 변수 이름은 속성 이름 및 형식과 일치해야 합니다. 일치는 대/소문자를 구분하지 않으며 [JsonPropertyName] 사용하여 속성 이름을 바꾸는 경우에도 생성자 매개 변수가 실제 속성 이름과 일치해야 합니다. 다음 예제에서는 TemperatureC
속성의 이름이 JSON에서 celsius
변경되지만 생성자 매개 변수의 이름은 여전히 temperatureC
.
using System.Text.Json;
using System.Text.Json.Serialization;
namespace ImmutableTypesCtorParms
{
public readonly struct Forecast
{
public DateTime Date { get; }
[JsonPropertyName("celsius")]
public int TemperatureC { get; }
public string Summary { get; }
[JsonConstructor]
public Forecast(DateTime date, int temperatureC, string summary) =>
(Date, TemperatureC, Summary) = (date, temperatureC, summary);
}
public class Program
{
public static void Main()
{
string json = """
{
"date":"2020-09-06T11:31:01.923395-07:00",
"celsius":-1,
"summary":"Cold"
}
""";
Console.WriteLine($"Input JSON: {json}");
var options = JsonSerializerOptions.Web;
Forecast forecast = JsonSerializer.Deserialize<Forecast>(json, options);
Console.WriteLine($"forecast.Date: {forecast.Date}");
Console.WriteLine($"forecast.TemperatureC: {forecast.TemperatureC}");
Console.WriteLine($"forecast.Summary: {forecast.Summary}");
string roundTrippedJson =
JsonSerializer.Serialize<Forecast>(forecast, options);
Console.WriteLine($"Output JSON: {roundTrippedJson}");
}
}
}
// Produces output like the following example:
//
//Input JSON: { "date":"2020-09-06T11:31:01.923395-07:00","celsius":-1,"summary":"Cold"}
//forecast.Date: 9 / 6 / 2020 11:31:01 AM
//forecast.TemperatureC: -1
//forecast.Summary: Cold
//Output JSON: { "date":"2020-09-06T11:31:01.923395-07:00","celsius":-1,"summary":"Cold"}
[JsonPropertyName]
외에도 다음 특성은 매개 변수가 있는 생성자를 사용하여 역직렬화를 지원합니다.
레코드
다음 예제와 같이 직렬화 및 역직렬화 모두에 대해 레코드가 지원됩니다.
using System.Text.Json;
namespace Records
{
public record Forecast(DateTime Date, int TemperatureC)
{
public string? Summary { get; init; }
};
public class Program
{
public static void Main()
{
Forecast forecast = new(DateTime.Now, 40)
{
Summary = "Hot!"
};
string forecastJson = JsonSerializer.Serialize<Forecast>(forecast);
Console.WriteLine(forecastJson);
Forecast? forecastObj = JsonSerializer.Deserialize<Forecast>(forecastJson);
Console.WriteLine(forecastObj);
}
}
}
// Produces output like the following example:
//
//{ "Date":"2020-10-21T15:26:10.5044594-07:00","TemperatureC":40,"Summary":"Hot!"}
//Forecast { Date = 10 / 21 / 2020 3:26:10 PM, TemperatureC = 40, Summary = Hot! }
속성에 property:
대상을 사용하여 속성 이름에 어떤 특성이든 적용할 수 있습니다. 위치 레코드에 대한 자세한 내용은 C# 언어 참조의 레코드에 대한 문서를 참조하세요.
비공개 멤버 및 속성 접근자
다음 예제와 같이 [JsonInclude] 특성을 사용하여 속성에 대한 비공용 접근자 사용하도록 설정할 수 있습니다.
using System.Text.Json;
using System.Text.Json.Serialization;
namespace NonPublicAccessors
{
public class Forecast
{
public DateTime Date { get; init; }
[JsonInclude]
public int TemperatureC { get; private set; }
[JsonInclude]
public string? Summary { private get; set; }
};
public class Program
{
public static void Main()
{
string json = """
{
"Date":"2020-10-23T09:51:03.8702889-07:00",
"TemperatureC":40,
"Summary":"Hot"
}
""";
Console.WriteLine($"Input JSON: {json}");
Forecast forecastDeserialized = JsonSerializer.Deserialize<Forecast>(json)!;
Console.WriteLine($"Date: {forecastDeserialized.Date}");
Console.WriteLine($"TemperatureC: {forecastDeserialized.TemperatureC}");
json = JsonSerializer.Serialize<Forecast>(forecastDeserialized);
Console.WriteLine($"Output JSON: {json}");
}
}
}
// Produces output like the following example:
//
//Input JSON: { "Date":"2020-10-23T09:51:03.8702889-07:00","TemperatureC":40,"Summary":"Hot"}
//Date: 10 / 23 / 2020 9:51:03 AM
//TemperatureC: 40
//Output JSON: { "Date":"2020-10-23T09:51:03.8702889-07:00","TemperatureC":40,"Summary":"Hot"}
Imports System.Text.Json
Imports System.Text.Json.Serialization
Namespace NonPublicAccessors
Public Class Forecast
Public Property [Date] As Date
Private _temperatureC As Integer
<JsonInclude>
Public Property TemperatureC As Integer
Get
Return _temperatureC
End Get
Private Set(Value As Integer)
_temperatureC = Value
End Set
End Property
Private _summary As String
<JsonInclude>
Public Property Summary As String
Private Get
Return _summary
End Get
Set(Value As String)
_summary = Value
End Set
End Property
End Class
Public NotInheritable Class Program
Public Shared Sub Main()
Dim json As String = "{""Date"":""2020-10-23T09:51:03.8702889-07:00"",""TemperatureC"":40,""Summary"":""Hot""}"
Console.WriteLine($"Input JSON: {json}")
Dim forecastDeserialized As Forecast = JsonSerializer.Deserialize(Of Forecast)(json)
Console.WriteLine($"Date: {forecastDeserialized.[Date]}")
Console.WriteLine($"TemperatureC: {forecastDeserialized.TemperatureC}")
json = JsonSerializer.Serialize(forecastDeserialized)
Console.WriteLine($"Output JSON: {json}")
End Sub
End Class
End Namespace
' Produces output like the following example:
'
'Input JSON: { "Date":"2020-10-23T09:51:03.8702889-07:00","TemperatureC":40,"Summary":"Hot"}
'Date: 10 / 23 / 2020 9:51:03 AM
'TemperatureC: 40
'Output JSON: { "Date":"2020-10-23T09:51:03.8702889-07:00","TemperatureC":40,"Summary":"Hot"}
속성에 프라이빗 setter를 포함하면 해당 속성을 역직렬화할 수 있습니다.
.NET 8 이상 버전에서는 [JsonInclude] 특성을 사용하여 지정된 형식의 serialization 계약에 공용이 아닌 멤버를 선택할 수도 있습니다.
메모
소스 생성 모드에서는 private
멤버를 직렬화하거나 [JsonInclude] 특성에 주석을 추가하여 private
접근자를 사용할 수 없습니다. 생성된 JsonSerializerContext와 동일한 어셈블리에 있는 경우에만 internal
멤버를 직렬화하거나 internal
접근자를 사용할 수 있습니다.
읽기 전용 속성
.NET 8 이상 버전에서는 읽기 전용 속성 또는 프라이빗 또는 퍼블릭 setter가 없는 속성도 역직렬화할 수 있습니다. 속성이 참조하는 인스턴스는 변경할 수 없지만 속성 형식이 변경 가능한 경우 수정할 수 있습니다. 예를 들어 목록에 요소를 추가할 수 있습니다. 읽기 전용 속성을 역직렬화하려면 개체 만들기 처리 동작을 바꿀대신 채우도록 설정해야 합니다. 예를 들어 JsonObjectCreationHandlingAttribute 특성으로 속성에 주석을 추가할 수 있습니다.
class A
{
[JsonObjectCreationHandling(JsonObjectCreationHandling.Populate)]
public List<int> Numbers1 { get; } = new List<int>() { 1, 2, 3 };
}
자세한 내용은 초기화된 속성 채우기참조하세요.
참고 항목
- System.Text.Json 개요
- JSON 직렬화 및 역직렬화하는 방법
.NET