뉴턴 소프트IEnumerable 유형의 속성을 가진 Json 직렬화 및 직렬화 해제 클래스
ASP를 소비하기 위해 코드를 이동하려고 합니다.NET MVC Web API가 SOAP Xml 대신 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 );
단, 대응하는 역직렬화는 실패합니다.
JsonConvert.DeserializeObject<SampleGroup>( sz );
다음 예외 메시지와 함께:
"JsonSerializationExample 유형의 인스턴스를 만들 수 없습니다.ISAAMPLE을 클릭합니다.Type은 인터페이스 또는 추상 클래스이므로 인스턴스화할 수 없습니다."
JsonConverter를 취득하면 다음과 같이 자산을 꾸밀 수 있습니다.
[JsonConverter( typeof (SamplesJsonConverter) )]
public IEnumerable<ISample> Samples { get; set; }
Json Converter는 다음과 같습니다.
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());
문서:커스텀 작성 컨버터
이것은 매우 심플하고 json.net에서 즉시 사용할 수 있는 지원입니다.시리얼라이즈 및 디시리얼라이즈 시에는 다음 Json Settings를 사용해야 합니다.
JsonConvert.SerializeObject(graph,Formatting.None, new JsonSerializerSettings()
{
TypeNameHandling =TypeNameHandling.Objects,
TypeNameAssemblyFormat = System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Simple
});
및 역직렬화의 경우 다음 코드를 사용합니다.
JsonConvert.DeserializeObject(Encoding.UTF8.GetString(bData),type,
new JsonSerializerSettings(){TypeNameHandling = TypeNameHandling.Objects}
);
중요한 JsonSerializerSettings 객체 이니셜라이저를 메모해 두십시오.
저는 Json Serializer Settings의 특별한 설정인 Type Name Handling을 사용하여 이 문제를 해결했습니다.모두
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에는 모든 종류의 기본 유형 필드가 있을 수 있으며 올바르게 일련화됩니다.
훌륭한 솔루션, 감사합니다!나는 Andy를 가져갔다.DBell의 질문과 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());
대부분의 경우 데이터 계약 전체를 제공하는 것이 아니라 요약이나 인터페이스 또는 그 목록을 포함하는 유형만 제공하기를 원합니다. 또한 이러한 인스턴스는 데이터 엔티티 내에서 매우 드물고 쉽게 식별할 수 있다는 점을 고려할 때 가장 쉽고 자세한 방법은 다음을 사용하는 것입니다.
[JsonProperty(ItemTypeNameHandling = TypeNameHandling.Objects)]
public IEnumerable<ISomeInterface> Items { get; set; }
속성으로 지정할 수 있습니다.이 속성에는 열거형/목록/수집이 포함됩니다.이는 해당 목록만 대상으로 하고 포함된 개체에 대한 다음과 같은 유형 정보만 추가합니다.
{
"Items": [
{
"$type": "Namespace.ClassA, Assembly",
"Property": "Value"
},
{
"$type": "Namespace.ClassB, Assembly",
"Property": "Value",
"Additional_ClassB_Property": 3
}
]
}
데이터 모델의 복잡성이 발생하는 장소에 깔끔하고 심플하게 배치하여 일부 컨버터에 숨길 필요가 없습니다.
언급URL : https://stackoverflow.com/questions/11754633/newtonsoft-json-serialize-and-deserialize-class-with-property-of-type-ienumerabl
'sourcetip' 카테고리의 다른 글
모의 MVC - 테스트할 요청 매개 변수 추가 (0) | 2023.03.19 |
---|---|
Angular JS 디렉티브 $destroy (0) | 2023.03.19 |
워드프레스 이미지에서 날짜를 제거하시겠습니까? (0) | 2023.03.14 |
TypeScript의 생성자 오버로드 (0) | 2023.03.14 |
Mongoose, 개체 배열에서 값 업데이트 (0) | 2023.03.14 |