Json.net은 파생 유형을 직렬화 / 역 직렬화합니까?


99

json.net (newtonsoft)
문서를 살펴보고 있지만 이것에 대한 내용이나 최선의 방법을 찾을 수 없습니다.

public class Base
{
    public string Name;
}
public class Derived : Base
{
    public string Something;
}

JsonConvert.Deserialize<List<Base>>(text);

이제 직렬화 된 목록에 Derived 개체가 있습니다. 목록을 역 직렬화하고 파생 된 형식을 다시 가져 오는 방법은 무엇입니까?


그것은 상속이 작동하는 방식이 아닙니다. JsonConvert.Deserialize <Derived> (text);를 지정할 수 있습니다. 이름 필드를 포함합니다. Derived 는 Base 이기 때문에 (다른 방법은 아님) Base는 Derived의 정의에 대해 아무것도 모릅니다.
— M.Babcock 2011

죄송합니다. 약간 설명했습니다. 문제는 기본 개체와 파생 개체를 모두 포함하는 목록이 있다는 것입니다. 따라서 파생 된 항목을 역 직렬화하는 방법을 newtonsoft에 알리는 방법을 알아 내야합니다.
— 윌

이 문제를 해결했습니다. 나도 같은 문제가 있습니다
— Luis Carlos Chavarría 2012-07-29

답변:


46

text이 시나리오에서와 같이 유형을 저장하는 경우 JsonSerializerSettings.

참조 : Newtonsoft JSON.NET을 사용하여 JSON을 IEnumerable <BaseType>으로 역 직렬화하는 방법

하지만 조심하세요. 다른 것을 사용 하면 보안 취약점에 노출TypeNameHandling = TypeNameHandling.None 될 수 있습니다 .


24
또한 사용할 수 있습니다 . 선언 된 유형 (예 :)이 인스턴스 유형 (예 :)과 일치하지 않는 경우에만 속성 TypeNameHandling = TypeNameHandling.Auto을 추가합니다 . 이렇게하면 JSON만큼 . $typeBaseDerivedTypeNameHandling.All
— AJ Richardson

JSON '..., ...'에 지정된 오류 해결 유형을 계속 수신합니다. 경로 '$ type', 줄 1, 위치 82. 아이디어가 있습니까?
— briba

3
공개 엔드 포인트에서 사용할 때는 보안 문제가 발생하므로주의하십시오. alphabot.com/security/blog/2017/net/…
— gjvdkamp

1
@gjvdkamp JEEZ 덕분에 이것에 대해 몰랐습니다. 내 게시물에 추가됩니다.
— kamranicus

96

유형 이름 처리를 활성화하고이를 설정 매개 변수로 (비) 직렬화기에 전달해야합니다.

Base object1 = new Base() { Name = "Object1" };
Derived object2 = new Derived() { Something = "Some other thing" };
List<Base> inheritanceList = new List<Base>() { object1, object2 };

JsonSerializerSettings settings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All };
string Serialized = JsonConvert.SerializeObject(inheritanceList, settings);
List<Base> deserializedList = JsonConvert.DeserializeObject<List<Base>>(Serialized, settings);

이로 인해 파생 클래스의 올바른 역 직렬화가 수행됩니다. 단점은 사용중인 모든 개체의 이름을 지정하므로 개체를 넣는 목록의 이름이 지정된다는 것입니다.


31
+1. SerializeObject 및 DeserializeObject에 대해 동일한 설정을 사용해야한다는 사실을 실제로 알 때까지 30 분 동안 인터넷 검색을했습니다. 역 직렬화 할 때 $ type을 암묵적으로 사용할 것이라고 생각했습니다.
— Erti-Chris Eelmaa

24
TypeNameHandling.Auto대부분의 필드 / 속성에 해당하는 필드 / 속성 유형과 일치 할 때 인스턴스 유형 이름을 작성하지 않기 때문에 더 좋습니다.
— Roman Starkov 2016

2
다른 솔루션 / 프로젝트에서 역 직렬화가 수행되는 경우에는 작동하지 않습니다. 직렬화시 솔루션 이름은 "SOLUTIONNAME.Models.Model"유형으로 포함됩니다. 다른 솔루션의 역 직렬화시 "JsonSerializationException : 'SOLUTIONNAME'어셈블리를로드 할 수 없습니다
— 슬픈 CRUD 개발자

19

질문이 매우 인기가 있기 때문에 유형 속성 이름과 해당 값을 제어하려는 경우 수행 할 작업을 추가하는 것이 유용 할 수 있습니다.

긴 방법은 JsonConvertertype 속성을 수동으로 확인하고 설정하여 직렬화를 처리 (역) 할 사용자 지정을 작성하는 것입니다 .

더 간단한 방법은 속성을 통해 모든 상용구를 처리 하는 JsonSubTypes 를 사용 하는 것입니다.

[JsonConverter(typeof(JsonSubtypes), "Sound")]
[JsonSubtypes.KnownSubType(typeof(Dog), "Bark")]
[JsonSubtypes.KnownSubType(typeof(Cat), "Meow")]
public class Animal
{
    public virtual string Sound { get; }
    public string Color { get; set; }
}

public class Dog : Animal
{
    public override string Sound { get; } = "Bark";
    public string Breed { get; set; }
}

public class Cat : Animal
{
    public override string Sound { get; } = "Meow";
    public bool Declawed { get; set; }
}

4
나는 필요성을 얻을 수 있지만, 나는 모든 "KnownSubType"S의 기본 클래스를 인식하게해야하는 팬 ... 아니에요
— 매트 놀즈

2
문서를 보면 다른 옵션이 있습니다. 나는 내가 더 좋아하는 예만을 제공했다.
— rzippo

1
이것은 역 직렬화시 임의 유형을로드하도록 서비스를 노출하지 않는 더 안전한 접근 방식입니다.
— David Burg

3

이 JsonKnownTypes를 사용하면 사용하는 것과 매우 유사하며 json에 판별자를 추가합니다.

[JsonConverter(typeof(JsonKnownTypeConverter<BaseClass>))]
[JsonKnownType(typeof(Base), "base")]
[JsonKnownType(typeof(Derived), "derived")]
public class Base
{
    public string Name;
}
public class Derived : Base
{
    public string Something;
}

당신이 직렬화 할 때 이제 JSON에서 개체가 추가됩니다 "$type"함께 "base"하고 "derived"가치가 직렬화에 사용됩니다

직렬화 된 목록 예 :

[
    {"Name":"some name", "$type":"base"},
    {"Name":"some name", "Something":"something", "$type":"derived"}
]
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.