我有一个接口,其中有一个像这样的属性:
public interface IFoo {
// ...
[JsonIgnore]
string SecretProperty { get; }
// ...
}
我希望在序列化所有实现类时忽略SecretProperty
。但似乎我必须在每个实现属性上定义JsonIgnore
属性。有没有一种方法可以在不必添加JsonIgnore
属性到每个实现中的情况下达到这个目的?我没有找到任何有帮助的序列化设置。
我有一个接口,其中有一个像这样的属性:
public interface IFoo {
// ...
[JsonIgnore]
string SecretProperty { get; }
// ...
}
我希望在序列化所有实现类时忽略SecretProperty
。但似乎我必须在每个实现属性上定义JsonIgnore
属性。有没有一种方法可以在不必添加JsonIgnore
属性到每个实现中的情况下达到这个目的?我没有找到任何有帮助的序列化设置。
经过一些搜索,我找到了这个问题:
如何使用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;
}
}
使用InterfaceContractResolver
在我的JsonSerializerSettings
中,任何接口中具有JsonIgnoreAttribute
的属性也会被忽略,即使它们具有JsonPropertyAttribute
(由于内部if
块的顺序)。
[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; }
}
然后在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
我相信这是在Json.NET 4.0.3中添加的,尽管在发布说明中没有明确提到JsonIgnore
:
新功能 - JsonObject和JsonProperty属性现在可以放置在接口上,并在序列化实现对象时使用。
(该实现可以在JsonTypeReflector.GetAttribute<T>(MemberInfo memberInfo)
中找到。)
然而,正如noted的Vitaly所指出的那样,在接口声明的类的基类中继承属性时,这种方法是行不通的。演示fiddle在这里。
我发现创建一个仅包含我想要的属性的DTO并将该对象序列化为JSON最简单。这样可以创建许多小的、上下文特定的对象,但管理代码库更容易,而且我不必考虑正在序列化的内容和忽略的内容。
你应该在类名前面添加[DataContract]
。
这会将默认值从包括所有属性更改为仅包括显式标记的属性。之后,在要包含在JSON输出中的每个属性前面添加[DataMember]
。