C# 向json.net添加自定义属性

C# 向json.net添加自定义属性,c#,.net,attributes,json.net,C#,.net,Attributes,Json.net,JSON.NET附带了属性属性,如[JsonIgnore]和[JsonProperty] 我想创建一些在序列化运行时运行的自定义程序,例如。 [JsonIgnoreSerialize]或[JsonIgnoreSerialize] 我如何扩展框架以包含此内容?由于您的目标是忽略序列化而不是反序列化的属性,因此可以使用ContractResolver 请注意,下面的类正是这样做的,它基于CamelCasePropertyNamesContractResolver,以确保它序列化为camelcased

JSON.NET附带了属性属性,如
[JsonIgnore]
[JsonProperty]

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


我如何扩展框架以包含此内容?

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

请注意,下面的类正是这样做的,它基于
CamelCasePropertyNamesContractResolver
,以确保它序列化为camelcased 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;
    }
}
该方法经过测试,也可用于嵌套对象。

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

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;
    }
}
公共类MyContractResolver:Newtonsoft.Json.Serialization.DefaultContractResolver
其中T:Attribute
{
类型_AttributeToIgnore=null;
公共MyContractResolver()
{
_AttributeToIgnore=类型(T);
}
受保护的重写IList CreateProperties(类型类型,MemberSerialization MemberSerialization)
{
var list=type.GetProperties()
.Where(x=>!x.GetCustomAttributes().Any(a=>a.GetType()==\u AttributeToIgnore))
.Select(p=>newjsonproperty()
{
PropertyName=p.名称,
PropertyType=p.PropertyType,
可读=正确,
可写=真,
ValueProvider=base.CreateMemberValueProvider(p)
}).ToList();
退货清单;
}
}
您可以在序列化/反序列化中使用它,如

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

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

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

public class MyJsonContractResolver : DefaultContractResolver
{
  protected override List<MemberInfo> GetSerializableMembers(Type objectType)
  {
    return base.GetSerializableMembers(objectType)
      .Where(mi => mi.GetCustomAttribute<JsonIgnoreSerializeAttribute>() != null)
      .ToList();
  }
}
公共类MyJsonContractResolver:DefaultContractResolver
{
受保护的覆盖列表GetSerializableMembers(类型objectType)
{
return base.GetSerializableMembers(objectType)
.Where(mi=>mi.GetCustomAttribute()!=null)
.ToList();
}
}

它们是否需要成为属性?您希望在自定义序列化属性中执行什么操作?我希望能够忽略序列化时的属性,但不能忽略反序列化时的属性。我认为只需在属性中添加一个属性(例如,
[JsonIgnoreSerialize]
)就很容易了。这个解决方案可以像广告中那样工作,但它有一个问题:它不遵守标准的Json.NET属性
[JsonIgnore]
和(更重要的是)
[JsonProperty]
。看见您应该首先调用
base.CreateProperties()
,然后根据自定义属性筛选该列表。请参阅。我更喜欢重写JsonPropertyAttribute的反序列化和序列化行为,而不是添加ContractResolver和调用序列化方法。有人知道它是如何实现的吗?我没有投反对票,但我想原因是您的解决方案实际上没有显示如何实现最初要求的自定义属性。相反,必须将要忽略的属性的名称传递给解析器,而解析器只处理单个属性。如果不止一个呢?很公平,布莱恩。谢谢你的建设性评论:)我已经用一个更合适的实现更新了我的答案。看起来更好。一个问题:您的
SerializeMyObject
方法的签名中有什么
TrackExtended
?那不应该是
对象
?绝对是。抱歉,这是我测试代码的示例的剩余部分;)-固定的!
var json = JsonConvert.SerializeObject(
            obj, 
            new JsonSerializerSettings() {
                ContractResolver = new MyContractResolver<JsonIgnoreSerialize>()
            });

var obj = JsonConvert.DeserializeObject<SomeType>(
            json, 
            new JsonSerializerSettings() {
                ContractResolver = new MyContractResolver<JsonIgnoreDeserialize>()
            });
public class MyJsonContractResolver : DefaultContractResolver
{
  protected override List<MemberInfo> GetSerializableMembers(Type objectType)
  {
    return base.GetSerializableMembers(objectType)
      .Where(mi => mi.GetCustomAttribute<JsonIgnoreSerializeAttribute>() != null)
      .ToList();
  }
}