Json.net으로 C # 객체를 직렬화하여 생성 된 구성 파일이 있습니다.
직렬화 된 클래스의 하나의 속성을 단순한 enum 속성이 아닌 클래스 속성으로 마이그레이션하려고합니다.
이 작업을 수행하는 한 가지 쉬운 방법은 이전 열거 형 속성을 클래스에 남겨두고 Json.net이 구성을로드 할 때이 속성을 읽도록 정렬하지만 다음에 객체를 직렬화 할 때 다시 저장하지 않도록하는 것입니다. 이전 열거 형에서 개별적으로 새 클래스를 생성하는 방법을 다룰 것입니다.
Json.net이 직렬화 할 때만 무시하고 역 직렬화 할 때주의하도록 C # 객체의 속성을 표시 (예 : 특성)하는 간단한 방법이 있습니까?
답변
실제로 원하는 결과를 얻기 위해 사용할 수있는 몇 가지 매우 간단한 접근 방식이 있습니다.
예를 들어 현재 다음과 같이 정의 된 클래스가 있다고 가정 해 보겠습니다.
class Config
{
public Fizz ObsoleteSetting { get; set; }
public Bang ReplacementSetting { get; set; }
}
enum Fizz { Alpha, Beta, Gamma }
class Bang
{
public string Value { get; set; }
}
그리고 당신은 이것을 원합니다 :
string json = @"{ ""ObsoleteSetting"" : ""Gamma"" }";
// deserialize
Config config = JsonConvert.DeserializeObject<Config>(json);
// migrate
config.ReplacementSetting =
new Bang { Value = config.ObsoleteSetting.ToString() };
// serialize
json = JsonConvert.SerializeObject(config);
Console.WriteLine(json);
이것을 얻으려면 :
{"ReplacementSetting":{"Value":"Gamma"}}
접근 방식 1 : ShouldSerialize 메서드 추가
Json.NET에는 ShouldSerialize
클래스에서 해당 메서드를 검색하여 속성을 조건부로 직렬화하는 기능이 있습니다 .
이 기능을 사용하려면 직렬화하지 않을 속성의 이름으로 대체 되는 부울 ShouldSerializeBlah()
메서드를 클래스에 추가합니다 Blah
. 이 메서드의 구현은 항상 false
.
class Config
{
public Fizz ObsoleteSetting { get; set; }
public Bang ReplacementSetting { get; set; }
public bool ShouldSerializeObsoleteSetting()
{
return false;
}
}
참고 :이 접근 방식이 마음에 들지만 ShouldSerialize
메서드 를 도입하여 클래스의 공용 인터페이스를 혼란스럽게하고 싶지 않은 경우 IContractResolver
를 사용하여 프로그래밍 방식으로 동일한 작업을 수행 할 수 있습니다 . 문서에서 조건부 속성 직렬화 를 참조하십시오 .
접근 방식 2 : JObject를 사용하여 JSON 조작
JsonConvert.SerializeObject
직렬화를 수행하는 데 사용 하는 대신 구성 개체를에로드 JObject
한 다음 작성하기 전에 JSON에서 원하지 않는 속성을 제거하기 만하면됩니다. 단지 몇 줄의 추가 코드입니다.
JObject jo = JObject.FromObject(config);
// remove the "ObsoleteSetting" JProperty from its parent
jo["ObsoleteSetting"].Parent.Remove();
json = jo.ToString();
접근법 3 : 속성의 영리한 (남용) 사용
- 적용
[JsonIgnore]
직렬화하지 않으려 속성에 속성을 . - 대체, 개인 추가원래 속성과 동일한 유형을 사용하여 클래스에 속성 setter를 . 해당 속성의 구현을 원래 속성으로 설정합니다.
[JsonProperty]
대체 setter에 속성을 적용 하여 원래 속성과 동일한 JSON 이름을 지정합니다.
수정 된 Config
클래스 는 다음과 같습니다 .
class Config
{
[JsonIgnore]
public Fizz ObsoleteSetting { get; set; }
[JsonProperty("ObsoleteSetting")]
private Fizz ObsoleteSettingAlternateSetter
{
// get is intentionally omitted here
set { ObsoleteSetting = value; }
}
public Bang ReplacementSetting { get; set; }
}
답변
deserialization 전용 속성을 내부로 표시하는 것이 허용되는 모든 상황에 대해 특성에 전혀 의존하지 않는 놀랍도록 간단한 솔루션이 있습니다. 속성을 내부 get으로 표시하기 만하면됩니다.
public class JsonTest {
public string SomeProperty { internal get; set; }
}
이로 인해 기본 설정 / 리졸버 등을 사용하여 올바른 역 직렬화가 이루어 지지만 속성은 직렬화 된 출력에서 제거됩니다.
답변
나는 이것에 대한 속성을 고수하는 것을 좋아합니다. 여기에 속성을 직렬화하지 않고 직렬화하지 않을 필요가 있거나 그 반대의 경우에 사용하는 방법이 있습니다.
1 단계-사용자 지정 속성 생성
public class JsonIgnoreSerializationAttribute : Attribute { }
2 단계-사용자 지정 계약 재조정 생성
class JsonPropertiesResolver : DefaultContractResolver
{
protected override List<MemberInfo> GetSerializableMembers(Type objectType)
{
//Return properties that do NOT have the JsonIgnoreSerializationAttribute
return objectType.GetProperties()
.Where(pi => !Attribute.IsDefined(pi, typeof(JsonIgnoreSerializationAttribute)))
.ToList<MemberInfo>();
}
}
3 단계-직렬화가 필요하지 않지만 역 직렬화가 필요한 속성 추가
[JsonIgnoreSerialization]
public string Prop1 { get; set; } //Will be skipped when serialized
[JsonIgnoreSerialization]
public string Prop2 { get; set; } //Also will be skipped when serialized
public string Prop3 { get; set; } //Will not be skipped when serialized
4 단계-사용
var sweet = JsonConvert.SerializeObject(myObj, new JsonSerializerSettings { ContractResolver = new JsonPropertiesResolver() });
도움이 되었기를 바랍니다! 또한 역 직렬화가 발생할 때 속성이 무시된다는 점에 주목할 가치가 있습니다. 역 직렬화 할 때 기존 방식으로 변환기를 사용합니다.
JsonConvert.DeserializeObject<MyType>(myString);
답변
setter 속성 사용 :
[JsonProperty(nameof(IgnoreOnSerializing))]
public string IgnoreOnSerializingSetter { set { _ignoreOnSerializing = value; } }
[JsonIgnore]
private string _ignoreOnSerializing;
[JsonIgnore]
public string IgnoreOnSerializing
{
get { return this._ignoreOnSerializing; }
set { this._ignoreOnSerializing = value; }
}
이 도움을 바랍니다.
답변
클래스 속성을 De-Serializable이고 Serializable이 아닌 플래그를 지정하는 방법을 검색하는 데 꽤 오랜 시간을 보낸 후 나는 그런 일이 전혀 없다는 것을 알았습니다. 그래서 두 개의 서로 다른 라이브러리 또는 직렬화 기술 (System.Runtime.Serialization.Json 및 Newtonsoft.Json)을 결합한 솔루션을 생각 해냈고 다음과 같이 작동했습니다.
- 모든 클래스 및 하위 클래스를 “DataContract”로 플래그 지정하십시오.
- 클래스 및 하위 클래스의 모든 속성을 “DataMember”로 플래그 지정합니다.
- 클래스 및 하위 클래스의 모든 속성을 “JsonProperty”로 플래그 지정합니다. 단, 직렬화하지 않기를 원하는 속성은 제외됩니다.
- 이제 속성을 “JsonIgnore”로 직렬화하지 않으려는 플래그를 지정하십시오.
-
그런 다음 “Newtonsoft.Json.JsonConvert.SerializeObject”를 사용하여 직렬화하고 “System.Runtime.Serialization.Json.DataContractJsonSerializer”를 사용하여 직렬화 해제합니다.
using System; using System.Collections.Generic; using Newtonsoft.Json; using System.Runtime.Serialization; using System.IO; using System.Runtime.Serialization.Json; using System.Text; namespace LUM_Win.model { [DataContract] public class User { public User() { } public User(String JSONObject) { MemoryStream stream = new MemoryStream(Encoding.Unicode.GetBytes(JSONObject)); DataContractJsonSerializer dataContractJsonSerializer = new DataContractJsonSerializer(typeof(User)); User user = (User)dataContractJsonSerializer.ReadObject(stream); this.ID = user.ID; this.Country = user.Country; this.FirstName = user.FirstName; this.LastName = user.LastName; this.Nickname = user.Nickname; this.PhoneNumber = user.PhoneNumber; this.DisplayPicture = user.DisplayPicture; this.IsRegistred = user.IsRegistred; this.IsConfirmed = user.IsConfirmed; this.VerificationCode = user.VerificationCode; this.Meetings = user.Meetings; } [DataMember(Name = "_id")] [JsonProperty(PropertyName = "_id")] public String ID { get; set; } [DataMember(Name = "country")] [JsonProperty(PropertyName = "country")] public String Country { get; set; } [DataMember(Name = "firstname")] [JsonProperty(PropertyName = "firstname")] public String FirstName { get; set; } [DataMember(Name = "lastname")] [JsonProperty(PropertyName = "lastname")] public String LastName { get; set; } [DataMember(Name = "nickname")] [JsonProperty(PropertyName = "nickname")] public String Nickname { get; set; } [DataMember(Name = "number")] [JsonProperty(PropertyName = "number")] public String PhoneNumber { get; set; } [DataMember(Name = "thumbnail")] [JsonProperty(PropertyName = "thumbnail")] public String DisplayPicture { get; set; } [DataMember(Name = "registered")] [JsonProperty(PropertyName = "registered")] public bool IsRegistred { get; set; } [DataMember(Name = "confirmed")] [JsonProperty(PropertyName = "confirmed")] public bool IsConfirmed { get; set; } [JsonIgnore] [DataMember(Name = "verification_code")] public String VerificationCode { get; set; } [JsonIgnore] [DataMember(Name = "meeting_ids")] public List<Meeting> Meetings { get; set; } public String toJSONString() { return JsonConvert.SerializeObject(this, new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore }); } } }
도움이되는 희망 …
답변
@ThoHo의 솔루션과 관련하여 setter를 사용하는 것이 실제로 필요한 모든 것이며 추가 태그가 없습니다.
저에게는 이전에 단일 참조 ID가 있었는데,이를로드하여 새 참조 ID 컬렉션에 추가하려고했습니다. 새 컬렉션에 값을 추가 한 setter 메서드 만 포함하도록 참조 ID의 정의를 변경합니다. Json은 Property에 get 이 없으면 값을 다시 쓸 수 없습니다 . 방법.
// Old property that I want to read from Json, but never write again. No getter.
public Guid RefId { set { RefIds.Add(value); } }
// New property that will be in use from now on. Both setter and getter.
public ICollection<Guid> RefIds { get; set; }
이 클래스는 이제 이전 버전과 역 호환되며 새 버전에 대한 RefId 만 저장합니다 .
답변
Tho Ho의 답변을 기반으로 필드에도 사용할 수 있습니다.
[JsonProperty(nameof(IgnoreOnSerializing))]
public string IgnoreOnSerializingSetter { set { IgnoreOnSerializing = value; } }
[JsonIgnore]
public string IgnoreOnSerializing;