使用JSON.net进行序列化时忽略接口中定义的属性

fer*_*ero 13 .net c# json.net

我有一个像这样的属性的接口:

public interface IFoo {
    // ...

    [JsonIgnore]
    string SecretProperty { get; }

    // ...
}
Run Code Online (Sandbox Code Playgroud)

我希望SecretProperty在序列化所有实现类时忽略它.但似乎我必须在JsonIgnore属性的每个实现上定义属性.有没有办法实现这一点,而无需将JsonIgnore属性添加到每个实现?我没有找到任何帮助我的序列化设置.

fer*_*ero 8

经过一番搜索,我发现了这个问题:

在使用JSON.NET对其进行序列化时,如何从接口继承该属性

我接受了Jeff Sternal的代码并添加了JsonIgnoreAttribute检测,所以它看起来像这样:

class InterfaceContractResolver : DefaultContractResolver
{
    public InterfaceContractResolver() : this(false) { }

    public InterfaceContractResolver(bool shareCache) : base(shareCache) { }

    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
    {
        var property = base.CreateProperty(member, memberSerialization);
        var interfaces = member.DeclaringType.GetInterfaces();
        foreach (var @interface in interfaces)
        {
            foreach (var interfaceProperty in @interface.GetProperties())
            {
                // This is weak: among other things, an implementation 
                // may be deliberately hiding an interface member
                if (interfaceProperty.Name == member.Name && interfaceProperty.MemberType == member.MemberType)
                {
                    if (interfaceProperty.GetCustomAttributes(typeof(JsonIgnoreAttribute), true).Any())
                    {
                        property.Ignored = true;
                        return property;
                    }

                    if (interfaceProperty.GetCustomAttributes(typeof(JsonPropertyAttribute), true).Any())
                    {
                        property.Ignored = false;
                        return property;
                    }
                }
            }
        }

        return property;
    }
}
Run Code Online (Sandbox Code Playgroud)

InterfaceContractResolver在我的使用中JsonSerializerSettings,所有具有JsonIgnoreAttribute任何接口的属性也被忽略,即使它们具有JsonPropertyAttribute(由于内部if块的顺序).


dbc*_*dbc 5

在 Json.NET 的最新版本中,只要属性是在声明接口的同一个类上声明的,应用[JsonIgnore]到接口属性现在就可以正常工作,并成功防止它们被所有实现类型序列化。不再需要自定义合同解析器。

例如,如果我们定义以下类型:

public interface IFoo 
{
    [JsonIgnore]
    string SecretProperty  { get; set; }

    string Include { get; set; }
}

public class Foo : IFoo 
{
    public string SecretProperty  { get; set; }
    public string Include { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

然后,以下测试在 Json.NET 11 和 12(也可能是早期版本)中通过:

var root = new Foo
{
    SecretProperty  = "Ignore Me",
    Include = "Include Me",
};

var json = JsonConvert.SerializeObject(root);

Assert.IsTrue(json == "{\"Include\":\"Include Me\"}");// Passes
Run Code Online (Sandbox Code Playgroud)

演示在这里这里

我相信这是在 Json.NET 4.0.3中添加的,尽管JsonIgnore发行说明中没有明确提及:

新功能 - JsonObject 和 JsonProperty 属性现在可以放置在接口上并在序列化实现对象时使用。

(可以在 中找到实现JsonTypeReflector.GetAttribute<T>(MemberInfo memberInfo)。)

然而,正如Vitaly指出的,当属性是从声明接口的类的基类继承时,这不起作用。演示小提琴在这里

  • 如果属性是从基类继承的,则它不起作用。使用版本 10 和 12 进行测试。此处演示:https://dotnetfiddle.net/eliVCu (3认同)