JSON.NET을 사용한 직렬화 된 필드의 순서 JSON 객체에서 필드 순서를 지정하는

JSON.NET을 사용하여 직렬화 된 JSON 객체에서 필드 순서를 지정하는 방법이 있습니까?

단일 필드가 항상 먼저 표시되도록 지정하면 충분합니다.



답변

지원되는 방법은 JsonProperty순서를 설정하려는 클래스 특성 에서 속성 을 사용하는 것입니다. 자세한 정보 는 JsonPropertyAttribute 주문 문서 를 읽으십시오 .

패스 JsonPropertyOrder값과 시리얼 라이저는 나머지를 다룰 것이다.

 [JsonProperty(Order = 1)]

이것은 매우 유사합니다

 DataMember(Order = 1) 

System.Runtime.Serialization일.

@ kevin-babcock의 중요한 메모는 다음과 같습니다.

… 순서를 1로 설정하면 다른 모든 속성에서 순서를 1보다 크게 설정 한 경우에만 작동합니다. 기본적으로 주문 설정이없는 속성은 -1의 순서로 제공됩니다. 따라서 모든 직렬화 된 속성과 순서를 제공하거나 첫 번째 항목을 -2로 설정해야합니다.


답변

의 메소드를 구현 IContractResolver하거나 재정 의하여 실제로 순서를 제어 할 수 있습니다 .DefaultContractResolverCreateProperties

다음 IContractResolver은 속성을 사전 순으로 정렬하는 간단한 구현의 예입니다 .

public class OrderedContractResolver : DefaultContractResolver
{
    protected override System.Collections.Generic.IList<JsonProperty> CreateProperties(System.Type type, MemberSerialization memberSerialization)
    {
        return base.CreateProperties(type, memberSerialization).OrderBy(p => p.PropertyName).ToList();
    }
}

그런 다음 설정을 설정하고 객체를 직렬화하면 JSON 필드가 알파벳 순서로 표시됩니다.

var settings = new JsonSerializerSettings()
{
    ContractResolver = new OrderedContractResolver()
};

var json = JsonConvert.SerializeObject(obj, Formatting.Indented, settings);

답변

제 경우에는 Mattias의 대답이 효과가 없었습니다. 이 CreateProperties메소드는 호출되지 않았습니다.

Newtonsoft.Json내부 디버깅을 마친 후에 다른 솔루션을 생각해 냈습니다.

public class JsonUtility
{
    public static string NormalizeJsonString(string json)
    {
        // Parse json string into JObject.
        var parsedObject = JObject.Parse(json);

        // Sort properties of JObject.
        var normalizedObject = SortPropertiesAlphabetically(parsedObject);

        // Serialize JObject .
        return JsonConvert.SerializeObject(normalizedObject);
    }

    private static JObject SortPropertiesAlphabetically(JObject original)
    {
        var result = new JObject();

        foreach (var property in original.Properties().ToList().OrderBy(p => p.Name))
        {
            var value = property.Value as JObject;

            if (value != null)
            {
                value = SortPropertiesAlphabetically(value);
                result.Add(property.Name, value);
            }
            else
            {
                result.Add(property.Name, property.Value);
            }
        }

        return result;
    }
}

답변

필자의 경우 niaher의 솔루션은 배열의 객체를 처리하지 않았기 때문에 작동하지 않았습니다.

그의 해결책을 바탕으로 이것은 내가 생각해 낸 것입니다.

public static class JsonUtility
{
    public static string NormalizeJsonString(string json)
    {
        JToken parsed = JToken.Parse(json);

        JToken normalized = NormalizeToken(parsed);

        return JsonConvert.SerializeObject(normalized);
    }

    private static JToken NormalizeToken(JToken token)
    {
        JObject o;
        JArray array;
        if ((o = token as JObject) != null)
        {
            List<JProperty> orderedProperties = new List<JProperty>(o.Properties());
            orderedProperties.Sort(delegate(JProperty x, JProperty y) { return x.Name.CompareTo(y.Name); });
            JObject normalized = new JObject();
            foreach (JProperty property in orderedProperties)
            {
                normalized.Add(property.Name, NormalizeToken(property.Value));
            }
            return normalized;
        }
        else if ((array = token as JArray) != null)
        {
            for (int i = 0; i < array.Count; i++)
            {
                array[i] = NormalizeToken(array[i]);
            }
            return array;
        }
        else
        {
            return token;
        }
    }
}

답변

Charlie가 언급했듯이 클래스 자체의 속성을 정렬하여 JSON 속성의 순서를 다소 제어 할 수 있습니다. 불행히도이 방법은 기본 클래스에서 상속 된 속성에는 적용되지 않습니다. 기본 클래스 속성은 코드에 배치 된대로 정렬되지만 기본 클래스 속성 앞에 나타납니다.

JSON 속성을 알파벳순으로 정렬해야하는 이유가 궁금한 사람은 원시 JSON 파일, 특히 속성이 많은 클래스가 주문 된 경우 작업하는 것이 훨씬 쉽습니다.


답변

이것은 일반 클래스, 사전 및 ExpandoObject (동적 객체)에서도 작동합니다.

class OrderedPropertiesContractResolver : DefaultContractResolver
    {
        protected override IList<JsonProperty> CreateProperties(System.Type type, MemberSerialization memberSerialization)
        {
            var props = base.CreateProperties(type, memberSerialization);
            return props.OrderBy(p => p.PropertyName).ToList();
        }
    }



class OrderedExpandoPropertiesConverter : ExpandoObjectConverter
    {
        public override bool CanWrite
        {
            get { return true; }
        }

        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            var expando = (IDictionary<string, object>)value;
            var orderedDictionary = expando.OrderBy(x => x.Key).ToDictionary(t => t.Key, t => t.Value);
            serializer.Serialize(writer, orderedDictionary);
        }
    }



var settings = new JsonSerializerSettings
        {
            ContractResolver = new OrderedPropertiesContractResolver(),
            Converters = { new OrderedExpandoPropertiesConverter() }
        };

var serializedString = JsonConvert.SerializeObject(obj, settings);

답변

JsonProperty Order모든 클래스 속성에 속성 을 넣고 싶지 않으면 자신의 ContractResolver를 만드는 것이 매우 간단합니다 …

IContractResolver 인터페이스는 JsonSerializer가 클래스에 속성을 배치하지 않고 .NET 객체를 JSON으로 직렬화 및 직렬화 해제하는 방법을 사용자 정의하는 방법을 제공합니다.

이처럼 :

private class SortedPropertiesContractResolver : DefaultContractResolver
{
    // use a static instance for optimal performance
    static SortedPropertiesContractResolver instance;

    static SortedPropertiesContractResolver() { instance = new SortedPropertiesContractResolver(); }

    public static SortedPropertiesContractResolver Instance { get { return instance; } }

    protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
    {
        var properties = base.CreateProperties(type, memberSerialization);
        if (properties != null)
            return properties.OrderBy(p => p.UnderlyingName).ToList();
        return properties;
    }
}

도구:

var settings = new JsonSerializerSettings { ContractResolver = SortedPropertiesContractResolver.Instance };
var json = JsonConvert.SerializeObject(obj, Formatting.Indented, settings);