简体   繁体   English

如何使用Json.Net将JsonProperty属性分配给DLL内的类的属性?

[英]How to assign JsonProperty attribute to properties of classes inside DLL using Json.Net?

I have a class inside a DLL which is not labelled with DataContract, JsonProperty etc. Now I want to serialize instance of the class as JSON objects, with the C# property names shortened . 我在DLL中有一个类,它没有标记DataContract, JsonProperty等。现在我想将类的实例序列化为JSON对象, 并缩短C#属性名称

For instance, the class is: 例如,该课程是:

public class Foo
{
    public string SomeLengthyCSharpPropertyName { get; set; }
}

I wonder if I could create a mapping between the C# names and the json names. 我想知道是否可以在C#名称和json名称之间创建映射。 I cannot directly add the DataContract, JsonProperty attributes like below. 我不能直接添加如下的DataContract, JsonProperty属性。 Is there any workaround? 有没有解决方法?

[DataContract]
public class Foo
{
    [JsonProperty("s")]
    public string SomeLengthyCSharpPropertyName { get; set; }
}

I tend not to create a another class with the same but JsonProperty -decorated properties and copy the properties to the new class and then serialize. 我倾向于不创建另一个具有相同但JsonProperty -decorated属性的类,并将属性复制到新类,然后序列化。

You can make your own custom ContractResolver with a dictionary of override attributes by member, then override CreateProperty() and apply the overrides to the JsonProperty returned by the base class: 您可以使用成员的覆盖属性字典创建自己的自定义ContractResolver ,然后重写CreateProperty()并将覆盖应用于基类返回的JsonProperty

public class JsonPropertyOverride
{
    public string PropertyName { get; set; }

    public bool? Ignored { get; set; }

    // Others as required from http://www.newtonsoft.com/json/help/html/T_Newtonsoft_Json_JsonPropertyAttribute.htm
    // Changing all value type properties to nullables.
}

public class OverrideContractResolver : DefaultContractResolver
{
    readonly Dictionary<MemberInfo, JsonPropertyOverride> overrides; // A private copy for thread safety.

    public OverrideContractResolver(IDictionary<MemberInfo, JsonPropertyOverride> overrides)
        : base()
    {
        if (overrides == null)
            throw new ArgumentNullException();
        this.overrides = overrides.ToDictionary(p => p.Key, p => p.Value);
    }

    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
    {
        var property = base.CreateProperty(member, memberSerialization);
        if (property != null)
        {
            JsonPropertyOverride attr;
            if (overrides.TryGetValue(member, out attr))
            {
                if (attr.PropertyName != null)
                    property.PropertyName = ResolvePropertyName(attr.PropertyName);
                if (attr.Ignored != null)
                    property.Ignored = attr.Ignored.Value;
            }
        }
        return property;
    }
}

You could also inherit from CamelCasePropertyNamesContractResolver if you prefer. 如果您愿意,也可以从CamelCasePropertyNamesContractResolver继承。

Then use it like: 然后使用它像:

public class Foo
{
    public string SomeLengthyCSharpPropertyName { get; set; }

    public string DefaultNotIgnored { get; set; }

    [JsonIgnore]
    public string DefaultIgnored { get; set; }
}

public class TestClass
{
    public static void Test()
    {
        var foo = new Foo { SomeLengthyCSharpPropertyName = "SomeLengthyCSharpPropertyName", DefaultIgnored = "DefaultIgnored", DefaultNotIgnored = "DefaultNotIgnored" };

        var resolver = new OverrideContractResolver(new Dictionary<MemberInfo, JsonPropertyOverride> { 
            { typeof(Foo).GetProperty("SomeLengthyCSharpPropertyName"), new JsonPropertyOverride { PropertyName = "c"  } }, 
            { typeof(Foo).GetProperty("DefaultNotIgnored"), new JsonPropertyOverride { Ignored = true  } }, 
            { typeof(Foo).GetProperty("DefaultIgnored"), new JsonPropertyOverride { Ignored = false  } }, 
        });
        var settings = new JsonSerializerSettings { ContractResolver = resolver };

        var json = JsonConvert.SerializeObject(foo, settings); // Outputs {"c":"SomeLengthyCSharpPropertyName","DefaultIgnored":"DefaultIgnored"}
        Debug.WriteLine(json);

        var expectedJson = @"{ ""c"": ""SomeLengthyCSharpPropertyName"", ""DefaultIgnored"": ""DefaultIgnored"" }";
        var ok = JToken.DeepEquals(JToken.Parse(json), JToken.Parse(expectedJson));
        Debug.Assert(ok); // No assert

        var foo2 = JsonConvert.DeserializeObject<Foo>(json, settings);

        var ok2 = foo2.DefaultIgnored == foo.DefaultIgnored && foo2.SomeLengthyCSharpPropertyName == foo.SomeLengthyCSharpPropertyName;
        Debug.Assert(ok2); // No assert
    }
}

It definitely feels like a workaround, but you might want to consider it. 这绝对是一种解决方法,但您可能想要考虑它。 If the class is not sealed, you can inherit from it, override it's properties (those you want to change) and then decorate them. 如果类没有被密封,你可以继承它,覆盖它的属性(你想要改变它们),然后装饰它们。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM