【问题标题】:Add a custom attribute to json.net向 json.net 添加自定义属性
【发布时间】:2015-10-02 13:45:47
【问题描述】:

JSON.NET 带有 [JsonIgnore][JsonProperty] 等属性属性。

我想创建一些在序列化运行时运行的自定义,例如 [JsonIgnoreSerialize] 或 [JsonIgnoreDeserialize]

我将如何扩展框架以包含它?

【问题讨论】:

  • 他们需要是属性吗?你想在你的自定义序列化属性中做什么?
  • 我希望能够忽略序列化而不是反序列化的属性。我认为只添加一个属性会很容易,例如[JsonIgnoreSerialize] 到酒店。

标签: c# .net attributes json.net


【解决方案1】:

您可以像这样编写自定义合约解析器

public class MyContractResolver<T> : Newtonsoft.Json.Serialization.DefaultContractResolver 
                                        where T : Attribute
{
    Type _AttributeToIgnore = null;

    public MyContractResolver()
    {
        _AttributeToIgnore = typeof(T);
    }

    protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
    {
        var list =  type.GetProperties()
                    .Where(x => !x.GetCustomAttributes().Any(a => a.GetType() == _AttributeToIgnore))
                    .Select(p => new JsonProperty()
                    {
                        PropertyName = p.Name,
                        PropertyType = p.PropertyType,
                        Readable = true,
                        Writable = true,
                        ValueProvider = base.CreateMemberValueProvider(p)
                    }).ToList();

        return list;
    }
}

你可以在序列化/反序列化中使用它

var json = JsonConvert.SerializeObject(
            obj, 
            new JsonSerializerSettings() {
                ContractResolver = new MyContractResolver<JsonIgnoreSerialize>()
            });

var obj = JsonConvert.DeserializeObject<SomeType>(
            json, 
            new JsonSerializerSettings() {
                ContractResolver = new MyContractResolver<JsonIgnoreDeserialize>()
            });

【讨论】:

  • 这个解决方案像宣传的那样工作,但它有一个问题:它不支持标准的 Json.NET 属性[JsonIgnore] 和(更重要的是)[JsonProperty]。见dotnetfiddle.net/Et265h。您应该首先调用base.CreateProperties(),然后根据自定义属性过滤该列表。见dotnetfiddle.net/gDGfrO
  • 我更喜欢重写JsonPropertyAttribute的反序列化和序列化行为,而不是添加ContractResolver和调用序列化方法。有人知道它是如何实现的吗?
【解决方案2】:

由于您的目标是忽略序列化而不是反序列化的属性,因此您可以使用ContractResolver

请注意,以下类就是这样做的,并且基于CamelCasePropertyNamesContractResolver,以确保它序列化为骆驼大小写的 Json 字段。如果你不想这样,你可以让它继承自DefaultContractResolver

另外,我自己的示例是基于字符串的名称,但您可以轻松检查属性是否由您的自定义属性修饰,而不是比较属性名称。

public class CamelCaseIgnoringPropertyJsonResolver<T> : CamelCasePropertyNamesContractResolver
{        
    protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
    {
        // list the properties to ignore
        var propertiesToIgnore =  type.GetProperties()
                .Where(x => x.GetCustomAttributes().OfType<T>().Any());

        // Build the properties list
        var properties = base.CreateProperties(type, memberSerialization);

        // only serialize properties that are not ignored
        properties = properties
            .Where(p => propertiesToIgnore.All(info => info.Name != p.UnderlyingName))
            .ToList();

        return properties;
    }
}

那么,你可以按如下方式使用它:

    static private string SerializeMyObject(object myObject)
    {
        var settings = new JsonSerializerSettings
        {
            ContractResolver = new CamelCaseIgnoringPropertyJsonResolver<JsonIgnoreSerializeAttribute>()
        };

        var json = JsonConvert.SerializeObject(myObject, settings);
        return json;
    }

最后,自定义属性可以是任何类型,但要匹配示例:

internal class JsonIgnoreSerializeAttribute : Attribute
{
}

该方法经过测试,也适用于嵌套对象。

【讨论】:

  • 我没有投反对票,但我猜原因是您的解决方案实际上并未按照最初的要求显示如何实现自定义属性。相反,必须将要忽略的属性名称传递给解析器,并且它只处理该单个属性。如果有多个怎么办?
  • 很公平,布赖恩。感谢您的建设性评论:)
  • 我已经用更合适的实现更新了我的答案。
  • 看起来更好。一个问题:TrackExtended 在您的SerializeMyObject 方法的签名中是什么?那不应该只是object吗?
  • 绝对。抱歉,这是我用来测试代码的样本的剩余部分;) - 已修复!
【解决方案3】:

不确定这是否是新的,但我建议使用直接处理成员信息的方法GetSerializableMembers。这样,就可以避免处理 JsonProperty。

public class MyJsonContractResolver : DefaultContractResolver
{
  protected override List<MemberInfo> GetSerializableMembers(Type objectType)
  {
    return base.GetSerializableMembers(objectType)
      .Where(mi => mi.GetCustomAttribute<JsonIgnoreSerializeAttribute>() != null)
      .ToList();
  }
}

【讨论】:

    猜你喜欢
    • 2015-03-09
    • 2018-08-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-25
    • 2013-04-15
    相关资源
    最近更新 更多