Json.net은 컴포지션에서 동시 수집으로 복잡한 객체를 역 직렬화합니다.

drqCode

다음과 같은 수업이 있습니다.

public class ComplexClass
{
    public ConcurrentBag<SimpleClass> _simpleClassObjects;
}

이 클래스를 직렬화하면 작동합니다. 하지만 역 직렬화하려고 할 때

public static ComplexClass LoadComplexClass()
    {
        ComplexClass persistedComplexClass;
        using (var stream = new StreamReader(File.Open(jsonFilePath, FileMode.Open)))
        {
            persistedComplexClass = (ComplexClass) JsonSerializer.Create().Deserialize(stream, typeof(ComplexClass));
        }
        return persistedComplexClass;
    }

예외가 발생합니다.

Newtonsoft.Json.dll에서 'System.InvalidCastException'유형의 처리되지 않은 예외가 발생했습니다.

추가 정보 : 'System.Collections.Concurrent.ConcurrentBag`1 [LabML.Model.Point]'유형의 개체를 'System.Collections.Generic.ICollection`1 [LabML.Model.Point]'유형으로 캐스팅 할 수 없습니다.

이 예외의 근본 원인 ConcurrentBag<T>은는 generic이 ICollection<T>아닌 non-generic 만 구현하기 때문 ICollection입니다.

Json.Net을 사용하여이 문제를 해결하는 방법은 무엇입니까? (나는 이것을 잠시 검색했지만 내가 찾은 유일한 것은 복잡한 클래스 ICollection<T>ConcurrentCollection아닌 매핑에 관한 것 입니다.

dbc

최신 정보

릴리스 10.0.3부터 Json.NET은 ConcurrentBag<T>. 릴리스 정보 에 따르면 :

  • 수정-ConcurrentStack / Queue / Bag 직렬화 수정

원래 답변

당신이 추측으로 문제가 있다는 것입니다 ConcurrentBag<T>구현은 ICollection하고 IEnumerable<T>있지만 ICollection<T>Json.NET 읽기 전용 컬렉션으로 그것에 항목과 치료를 추가하는 방법을 알고하지 않도록. 입력 컬렉션을받는 매개 변수화 된 생성자ConcurrentBag<T>있지만 Json.NET은 내부적으로 콜백을 가지고 있기 때문에 해당 생성자를 사용하지 않습니다 . Json.NET은 이러한 콜백이있을 때 매개 변수화 된 생성자를 사용하지 않고 대신 예외를 발생시킵니다.[OnSerializing][OnDeserialized]

Cannot call OnSerializing on an array or readonly list, or list created from a non-default constructor: System.Collections.Concurrent.ConcurrentBag`1[]

따라서 만들 필요가 사용자 정의JsonConverter 를 들어 ConcurrentBag<T>:

public class ConcurrentBagConverter : ConcurrentBagConverterBase
{
    public override bool CanConvert(Type objectType)
    {
        return objectType.GetConcurrentBagItemType() != null;
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.Null)
            return null;
        try
        {
            var itemType = objectType.GetConcurrentBagItemType();
            var method = GetType().GetMethod("ReadJsonGeneric", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy);
            var genericMethod = method.MakeGenericMethod(new[] { objectType, itemType });
            return genericMethod.Invoke(this, new object[] { reader, objectType, itemType, existingValue, serializer });
        }
        catch (TargetInvocationException ex)
        {
            // Wrap the TargetInvocationException in a JsonSerializationException
            throw new JsonSerializationException("Failed to deserialize " + objectType, ex);
        }
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        var objectType = value.GetType();
        try
        {
            var itemType = objectType.GetConcurrentBagItemType();
            var method = GetType().GetMethod("WriteJsonGeneric", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy);
            var genericMethod = method.MakeGenericMethod(new[] { objectType, itemType });
            genericMethod.Invoke(this, new object[] { writer, value, serializer });
        }
        catch (TargetInvocationException ex)
        {
            // Wrap the TargetInvocationException in a JsonSerializationException
            throw new JsonSerializationException("Failed to serialize " + objectType, ex);
        }
    }
}

public class ConcurrentBagConverter<TItem> : ConcurrentBagConverterBase
{
    public override bool CanConvert(Type objectType)
    {
        return typeof(ConcurrentBagConverter<TItem>).IsAssignableFrom(objectType);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        return ReadJsonGeneric<ConcurrentBag<TItem>, TItem>(reader, objectType, typeof(TItem), existingValue, serializer);
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        WriteJsonGeneric<ConcurrentBag<TItem>, TItem>(writer, value, serializer);
    }
}

// https://stackoverflow.com/questions/42836648/json-net-deserialize-complex-object-with-concurrent-collection-in-composition
public abstract class ConcurrentBagConverterBase : JsonConverter
{
    protected TConcurrentBag ReadJsonGeneric<TConcurrentBag, TItem>(JsonReader reader, Type collectionType, Type itemType, object existingValue, JsonSerializer serializer)
        where TConcurrentBag : ConcurrentBag<TItem>
    {
        if (reader.TokenType == JsonToken.Null)
            return null;
        if (reader.TokenType != JsonToken.StartArray)
            throw new JsonSerializationException(string.Format("Expected {0}, encountered {1} at path {2}", JsonToken.StartArray, reader.TokenType, reader.Path));
        var collection = existingValue as TConcurrentBag ?? (TConcurrentBag)serializer.ContractResolver.ResolveContract(collectionType).DefaultCreator();
        while (reader.Read())
        {
            switch (reader.TokenType)
            {
                case JsonToken.Comment:
                    break;
                case JsonToken.EndArray:
                    return collection;
                default:
                    collection.Add((TItem)serializer.Deserialize(reader, itemType));
                    break;
            }
        }
        // Should not come here.
        throw new JsonSerializationException("Unclosed array at path: " + reader.Path);
    }

    protected void WriteJsonGeneric<TConcurrentBag, TItem>(JsonWriter writer, object value, JsonSerializer serializer)
        where TConcurrentBag : ConcurrentBag<TItem>
    {
        // Snapshot the bag as an array and serialize the array.
        var array = ((TConcurrentBag)value).ToArray();
        serializer.Serialize(writer, array);
    }
}

internal static class TypeExtensions
{
    public static Type GetConcurrentBagItemType(this Type objectType)
    {
        while (objectType != null)
        {
            if (objectType.IsGenericType
                && objectType.GetGenericTypeDefinition() == typeof(ConcurrentBag<>))
            {
                return objectType.GetGenericArguments()[0];
            }
            objectType = objectType.BaseType;
        }
        return null;
    }
}

public class ConcurrentBagContractResolver : DefaultContractResolver
{
    protected override JsonArrayContract CreateArrayContract(Type objectType)
    {
        var contract = base.CreateArrayContract(objectType);

        var concurrentItemType = objectType.GetConcurrentBagItemType();
        if (concurrentItemType != null)
        {
            if (contract.Converter == null)
                contract.Converter = (JsonConverter)Activator.CreateInstance(typeof(ConcurrentBagConverter<>).MakeGenericType(new[] { concurrentItemType }));
        }

        return contract;
    }
}

그런 다음 다음과 같이 특정 필드에 일반 버전을 적용하십시오.

public class ComplexClass
{
    [JsonConverter(typeof(ConcurrentBagConverter<SimpleClass>))]
    public ConcurrentBag<SimpleClass> _simpleClassObjects;
}

또는 다음 설정을 사용하여 모두에 ConcurrentBag<T>대해 전체적으로 범용 버전을 적용합니다 T.

var settings = new JsonSerializerSettings
{
    Converters = { new ConcurrentBagConverter() },
};

또는 범용 변환기를 사용하는 것보다 약간 더 나은 성능을 가질 수있는 사용자 지정 계약 해결 프로그램을 사용할 수 있습니다.

var settings = new JsonSerializerSettings
{
    ContractResolver = new ConcurrentBagContractResolver(),
};

예제 바이올린 .

즉, 위의 내용은 ConcurrentBag<T>속성 또는 필드가 읽기 / 쓰기 인 경우에만 작동합니다 . 멤버가 읽기 전용이면 컬렉션 멤버와 콘텐츠가 모두 읽기 전용이라고 추론하기 때문에 변환기가 있어도 Json.NET 9.0.1이 역 직렬화를 건너 뜁니다 . (이것은에서 버그 일 수 있습니다 JsonSerializerInternalReader.CalculatePropertyDetails().)

해결 방법으로 속성을 비공개로 설정하고 다음과 같이 표시 할 수 있습니다 [JsonProperty].

public class ComplexClass
{
    ConcurrentBag<SimpleClass> m_simpleClassObjects = new ConcurrentBag<SimpleClass>();

    [JsonConverter(typeof(ConcurrentBagConverter<SimpleClass>))]
    [JsonProperty]
    public ConcurrentBag<SimpleClass> _simpleClassObjects { get { return m_simpleClassObjects; } private set { m_simpleClassObjects = value; } }
}

또는 서로 게이트 배열 속성을 사용하여 모든 종류의 변환기가 필요하지 않습니다.

public class ComplexClass
{
    readonly ConcurrentBag<SimpleClass> m_simpleClassObjects = new ConcurrentBag<SimpleClass>();

    [JsonIgnore]
    public ConcurrentBag<SimpleClass> _simpleClassObjects { get { return m_simpleClassObjects; } }

    [JsonProperty("_simpleClassObjects")]
    SimpleClass[] _simpleClassObjectsArray
    {
        get
        {
            return _simpleClassObjects.ToArray();
        }
        set
        {
            if (value == null)
                return;
            foreach (var item in value)
                _simpleClassObjects.Add(item);
        }
    }
}

이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.

침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제

에서 수정
0

몇 마디 만하겠습니다

0리뷰
로그인참여 후 검토

관련 기사

분류에서Dev

Json .Net은 플랫 객체를 복잡한 객체로 직렬화합니다 (직렬화 / 역 직렬화에 대한 객체 구조 변경).

분류에서Dev

Json.net은 이름이 다른 동일한 객체를 역 직렬화합니다.

분류에서Dev

json.net은 C #에서 json 객체를 역 직렬화합니다.

분류에서Dev

DynamicJsonArray가있는 복잡한 JSON 개체를 동적으로 역 직렬화

분류에서Dev

Json.Net은 JSON 객체를 역 직렬화합니다.

분류에서Dev

복잡한 Json 객체 역 직렬화

분류에서Dev

Json은 인터페이스를 속성으로 사용하여 복잡한 개체를 역 직렬화합니다.

분류에서Dev

Newton JSON은 객체로 역 직렬화합니다.

분류에서Dev

GSON은 복잡한 객체 배열을 역 직렬화합니다.

분류에서Dev

VB.NET은 Newtonsoft JSON을 개체로 동적으로 역 직렬화합니다.

분류에서Dev

C #에서는 간단한 JSON 개체를 정수 목록으로 역 직렬화합니다.

분류에서Dev

XML은 동일한 객체 다른 요소 이름으로 역 직렬화합니다.

분류에서Dev

복잡한 JSON 개체 역 직렬화

분류에서Dev

C #에서 복잡한 json 파일을 역 직렬화하려고합니다.

분류에서Dev

Json.net은 객체 목록을 역 직렬화하지 않습니다.

분류에서Dev

Json.Net은 여러 제네릭 유형으로 객체를 역 직렬화 할 수 없습니까?

분류에서Dev

복잡한 json 파일을 POJO로 역 직렬화-하나의 목록 요소로 작동하거나 작동하지 않습니다.

분류에서Dev

중첩 된 개체를 역 직렬화하는 Json.NET은 JsonProperty.Required를 무시합니다.

분류에서Dev

복잡한 자바 객체를 부분적으로 역 직렬화하기

분류에서Dev

JSON을 .net 객체로 역 직렬화

분류에서Dev

Json.net을 사용하여 Vb.net에서 JSON 객체를 어떻게 역 직렬화합니까?

분류에서Dev

Json.Net 역 직렬화로 인해 null 개체가 발생합니다.

분류에서Dev

Jackson API-간단한 동적 객체로 JSON 역 직렬화

분류에서Dev

json 결과를 동적 객체로 역 직렬화

분류에서Dev

다양한 유형의 객체를 포함하는 JSON 배열 역 직렬화

분류에서Dev

GSON은 Android에서 두 가지 유형의 객체로 목록을 역 직렬화합니다.

분류에서Dev

복잡한 객체 목록을 JSON으로 직렬화

분류에서Dev

복잡한 모델 개체에 대한 MVC 형식 사후 역 직렬화가 불완전합니다.

분류에서Dev

복잡한 Swift 객체를 AWS Lambda 페이로드로 올바르게 직렬화 / 역 직렬화하려면 어떻게해야합니까?

Related 관련 기사

  1. 1

    Json .Net은 플랫 객체를 복잡한 객체로 직렬화합니다 (직렬화 / 역 직렬화에 대한 객체 구조 변경).

  2. 2

    Json.net은 이름이 다른 동일한 객체를 역 직렬화합니다.

  3. 3

    json.net은 C #에서 json 객체를 역 직렬화합니다.

  4. 4

    DynamicJsonArray가있는 복잡한 JSON 개체를 동적으로 역 직렬화

  5. 5

    Json.Net은 JSON 객체를 역 직렬화합니다.

  6. 6

    복잡한 Json 객체 역 직렬화

  7. 7

    Json은 인터페이스를 속성으로 사용하여 복잡한 개체를 역 직렬화합니다.

  8. 8

    Newton JSON은 객체로 역 직렬화합니다.

  9. 9

    GSON은 복잡한 객체 배열을 역 직렬화합니다.

  10. 10

    VB.NET은 Newtonsoft JSON을 개체로 동적으로 역 직렬화합니다.

  11. 11

    C #에서는 간단한 JSON 개체를 정수 목록으로 역 직렬화합니다.

  12. 12

    XML은 동일한 객체 다른 요소 이름으로 역 직렬화합니다.

  13. 13

    복잡한 JSON 개체 역 직렬화

  14. 14

    C #에서 복잡한 json 파일을 역 직렬화하려고합니다.

  15. 15

    Json.net은 객체 목록을 역 직렬화하지 않습니다.

  16. 16

    Json.Net은 여러 제네릭 유형으로 객체를 역 직렬화 할 수 없습니까?

  17. 17

    복잡한 json 파일을 POJO로 역 직렬화-하나의 목록 요소로 작동하거나 작동하지 않습니다.

  18. 18

    중첩 된 개체를 역 직렬화하는 Json.NET은 JsonProperty.Required를 무시합니다.

  19. 19

    복잡한 자바 객체를 부분적으로 역 직렬화하기

  20. 20

    JSON을 .net 객체로 역 직렬화

  21. 21

    Json.net을 사용하여 Vb.net에서 JSON 객체를 어떻게 역 직렬화합니까?

  22. 22

    Json.Net 역 직렬화로 인해 null 개체가 발생합니다.

  23. 23

    Jackson API-간단한 동적 객체로 JSON 역 직렬화

  24. 24

    json 결과를 동적 객체로 역 직렬화

  25. 25

    다양한 유형의 객체를 포함하는 JSON 배열 역 직렬화

  26. 26

    GSON은 Android에서 두 가지 유형의 객체로 목록을 역 직렬화합니다.

  27. 27

    복잡한 객체 목록을 JSON으로 직렬화

  28. 28

    복잡한 모델 개체에 대한 MVC 형식 사후 역 직렬화가 불완전합니다.

  29. 29

    복잡한 Swift 객체를 AWS Lambda 페이로드로 올바르게 직렬화 / 역 직렬화하려면 어떻게해야합니까?

뜨겁다태그

보관