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.