NewtonSoft.Json 유형 IEnumerable의 속성을 사용하여 클래스 직렬화 및 역 직렬화
SOAP Xml 대신 ASP.NET MVC 웹 API 생성 Json 데이터를 사용하기 위해 일부 코드를 이동하려고합니다.
유형의 속성을 직렬화 및 역 직렬화하는 데 문제가 있습니다.
IEnumerable<ISomeInterface>.
다음은 간단한 예입니다.
public interface ISample{
int SampleId { get; set; }
}
public class Sample : ISample{
public int SampleId { get; set; }
}
public class SampleGroup{
public int GroupId { get; set; }
public IEnumerable<ISample> Samples { get; set; }
}
}
다음을 사용하여 SampleGroup의 인스턴스를 쉽게 직렬화 할 수 있습니다.
var sz = JsonConvert.SerializeObject( sampleGroupInstance );
그러나 해당 deserialize가 실패합니다.
JsonConvert.DeserializeObject<SampleGroup>( sz );
이 예외 메시지와 함께 :
"JsonSerializationExample.ISample 유형의 인스턴스를 만들 수 없습니다. 유형은 인터페이스 또는 추상 클래스이며 인스턴스화 할 수 없습니다."
JsonConverter를 파생하면 다음과 같이 속성을 장식 할 수 있습니다.
[JsonConverter( typeof (SamplesJsonConverter) )]
public IEnumerable<ISample> Samples { get; set; }
다음은 JsonConverter입니다.
public class SamplesJsonConverter : JsonConverter{
public override bool CanConvert( Type objectType ){
return ( objectType == typeof (IEnumerable<ISample>) );
}
public override object ReadJson( JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer ){
var jA = JArray.Load( reader );
return jA.Select( jl => serializer.Deserialize<Sample>( new JTokenReader( jl ) ) ).Cast<ISample>( ).ToList( );
}
public override void WriteJson( JsonWriter writer, object value, JsonSerializer serializer ){
... What works here?
}
}
이 변환기는 역 직렬화 문제를 해결하지만 직렬화가 다시 작동하도록 WriteJson 메서드를 코딩하는 방법을 알 수 없습니다.
아무도 도울 수 있습니까?
이것이 처음에 문제를 해결하는 "올바른"방법입니까?
을 사용할 필요가없고 JsonConverterAttribute, 모델을 깨끗하게 유지하고, 사용할 필요도 없습니다 CustomCreationConverter. 코드는 더 간단합니다.
public class SampleConverter : CustomCreationConverter<ISample>
{
public override ISample Create(Type objectType)
{
return new Sample();
}
}
그때:
var sz = JsonConvert.SerializeObject( sampleGroupInstance );
JsonConvert.DeserializeObject<SampleGroup>( sz, new SampleConverter());
문서 : CustomCreationConverter로 역 직렬화
json.net에서 제공하는 매우 간단하고 즉시 사용 가능한 지원이므로 직렬화 및 역 직렬화하는 동안 다음 JsonSettings를 사용해야합니다.
JsonConvert.SerializeObject(graph,Formatting.None, new JsonSerializerSettings()
{
TypeNameHandling =TypeNameHandling.Objects,
TypeNameAssemblyFormat = System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Simple
});
Deserialzing의 경우 아래 코드를 사용하십시오.
JsonConvert.DeserializeObject(Encoding.UTF8.GetString(bData),type,
new JsonSerializerSettings(){TypeNameHandling = TypeNameHandling.Objects}
);
중요한 JsonSerializerSettings 개체 이니셜 라이저를 기록해 두십시오.
TypeNameHandling.All 이라는 JsonSerializerSettings에 대한 특수 설정을 사용 하여이 문제를 해결했습니다.
TypeNameHandling 설정은 JSON 직렬화시 유형 정보를 포함하고 JSON 역 직렬화시 생성 유형이 생성되도록 유형 정보를 읽습니다.
직렬화 :
var settings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All };
var text = JsonConvert.SerializeObject(configuration, settings);
역 직렬화 :
var settings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All };
var configuration = JsonConvert.DeserializeObject<YourClass>(json, settings);
YourClass 클래스 는 모든 종류의 기본 유형 필드를 가질 수 있으며 올바르게 직렬화됩니다.
훌륭한 솔루션, 감사합니다! 나는 AndyDBell의 질문과 Cuong Le의 대답을 사용하여 두 가지 다른 인터페이스 구현으로 예제를 빌드했습니다.
public interface ISample
{
int SampleId { get; set; }
}
public class Sample1 : ISample
{
public int SampleId { get; set; }
public Sample1() { }
}
public class Sample2 : ISample
{
public int SampleId { get; set; }
public String SampleName { get; set; }
public Sample2() { }
}
public class SampleGroup
{
public int GroupId { get; set; }
public IEnumerable<ISample> Samples { get; set; }
}
class Program
{
static void Main(string[] args)
{
//Sample1 instance
var sz = "{\"GroupId\":1,\"Samples\":[{\"SampleId\":1},{\"SampleId\":2}]}";
var j = JsonConvert.DeserializeObject<SampleGroup>(sz, new SampleConverter<Sample1>());
foreach (var item in j.Samples)
{
Console.WriteLine("id:{0}", item.SampleId);
}
//Sample2 instance
var sz2 = "{\"GroupId\":1,\"Samples\":[{\"SampleId\":1, \"SampleName\":\"Test1\"},{\"SampleId\":2, \"SampleName\":\"Test2\"}]}";
var j2 = JsonConvert.DeserializeObject<SampleGroup>(sz2, new SampleConverter<Sample2>());
//Print to show that the unboxing to Sample2 preserved the SampleName's values
foreach (var item in j2.Samples)
{
Console.WriteLine("id:{0} name:{1}", item.SampleId, (item as Sample2).SampleName);
}
Console.ReadKey();
}
}
그리고 SampleConverter의 일반 버전 :
public class SampleConverter<T> : CustomCreationConverter<ISample> where T: new ()
{
public override ISample Create(Type objectType)
{
return ((ISample)new T());
}
}
내 프로젝트에서이 코드는 항상 특별한 변환기가없는 것처럼 지정된 값을 직렬화하는 기본 직렬화기로 작동했습니다.
serializer.Serialize(writer, value);
나는 이것을 작동시켰다.
명시 적 변환
public override object ReadJson(JsonReader reader, Type objectType, object existingValue,
JsonSerializer serializer)
{
var jsonObj = serializer.Deserialize<List<SomeObject>>(reader);
var conversion = jsonObj.ConvertAll((x) => x as ISomeObject);
return conversion;
}
가지고있는 것 :
public interface ITerm
{
string Name { get; }
}
public class Value : ITerm...
public class Variable : ITerm...
public class Query
{
public IList<ITerm> Terms { get; }
...
}
다음을 구현하는 전환 트릭을 관리했습니다.
public class TermConverter : JsonConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var field = value.GetType().Name;
writer.WriteStartObject();
writer.WritePropertyName(field);
writer.WriteValue((value as ITerm)?.Name);
writer.WriteEndObject();
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue,
JsonSerializer serializer)
{
var jsonObject = JObject.Load(reader);
var properties = jsonObject.Properties().ToList();
var value = (string) properties[0].Value;
return properties[0].Name.Equals("Value") ? (ITerm) new Value(value) : new Variable(value);
}
public override bool CanConvert(Type objectType)
{
return typeof (ITerm) == objectType || typeof (Value) == objectType || typeof (Variable) == objectType;
}
}
다음과 같이 JSON에서 직렬화 및 역 직렬화 할 수 있습니다.
string JsonQuery = "{\"Terms\":[{\"Value\":\"This is \"},{\"Variable\":\"X\"},{\"Value\":\"!\"}]}";
...
var query = new Query(new Value("This is "), new Variable("X"), new Value("!"));
var serializeObject = JsonConvert.SerializeObject(query, new TermConverter());
Assert.AreEqual(JsonQuery, serializeObject);
...
var queryDeserialized = JsonConvert.DeserializeObject<Query>(JsonQuery, new TermConverter());
'Program Club' 카테고리의 다른 글
| Symfony2에서 ObjectManager와 EntityManager의 차이점은 무엇입니까? (0) | 2020.11.24 |
|---|---|
| ConcurrentDictionary.TryAdd가 실패 할 수 있습니까? (0) | 2020.11.24 |
| 두 구문의 의미 적 유사성을 알려주는 알고리즘이 있습니까? (0) | 2020.11.24 |
| ASP.NET MVC 컨트롤러 수명주기 (0) | 2020.11.24 |
| requestAnimationFrame 재귀 / 루프를 중지하는 방법은 무엇입니까? (0) | 2020.11.23 |