我遇到了一个奇怪的情况,其中 IgnoreDataMember
没有完成这项工作,但 JsonIgnore
却做了。
在这种情况下,我从具有 public {get; set;}
属性的类继承,并且我选择用 NotSupportedException
覆盖 setter。我只希望序列化程序能够设置属性,而不是用户,但我希望用户得到它,所以我做了以下工作:
[DataContract]
public class BaseObject : BaseInterface
{
[DataMember]
public virtual double information { get; set; }
}
[DataContract]
public class ServerGeneratedObject : BaseObject
{
[IgnoreDataMember]
public override double information {
get { return server_set_information; }
set { throw new NotSupportedException("Server generated property"); }
}
[DataMember(Name="information")]
private double server_set_information { get; set; }
}
不幸的是,这会引发错误“'ServerGeneratedObject' 上已经存在名为'information' 的成员。使用 JsonPropertyAttribute 指定另一个名称。”
但是,如果我使用 [JsonIgnore] 属性,这将按预期工作。这似乎是由于数据契约(Contract)解析器 (code currently lives here) 的这一部分造成的:
bool flag2 = JsonTypeReflector.GetAttribute<JsonIgnoreAttribute>(attributeProvider) != null ||
JsonTypeReflector.GetAttribute<JsonExtensionDataAttribute>(attributeProvider) != null ||
JsonTypeReflector.GetAttribute<NonSerializedAttribute>(attributeProvider) != null;
if (memberSerialization != MemberSerialization.OptIn)
{
bool flag3 = JsonTypeReflector.GetAttribute<IgnoreDataMemberAttribute>(attributeProvider) != null;
property.Ignored = flag2 | flag3;
}
该属性未正确设置为“忽略”,因为它处于“OptIn”模式,但如果是这种情况,我不知道为什么“选择加入”继承的“信息”属性,因为“DataMember”属性是不应该是可继承的。我提交了一个错误 here 以防这不是预期的行为。
有什么我可以在这里做的吗?我试图避免在我的公共(public)数据模型上使用任何“Newtonsoft”属性,因为我不希望使用我的客户端库对象模型的人必须引用 Newtonsoft 程序集。
最佳答案
我怀疑您所看到的逻辑是为了使 Json.NET 与 DataContractJsonSerializer
一致,在属性同时标记有 [DataContract]
和 [IgnoreDataContract]
的情况下。完成后,[DataContract]
将优先,数据契约序列化器 将输出 属性。例如。连载
[DataContract]
public class Test
{
[DataMember]
[IgnoreDataMember]
public virtual double information { get; set; }
}
结果为
{"information":0}
。(逻辑也可能是一个效率调整。在简单的情况下,如果一个类型用
[DataContract]
标记,那么 [IgnoreDataMember]
是多余的,所以不需要花时间用反射检查它。)可能正因为如此, Json.NET 和
DataContractJsonSerializer
都会抛出异常序列化派生类,该派生类覆盖其基类中的数据成员属性,用 [IgnoreDataMember]
标记覆盖的属性,然后添加具有相同数据成员名称的不相关属性.如果您尝试这样做,Json.NET 会抛出您看到的异常——而 DataContractJsonSerializer
也会抛出异常:System.Runtime.Serialization.SerializationException occurred
Message="The data contract type 'Question38020614.ServerGeneratedObject' is not serializable with DataContractJsonSerializer because the data member 'information' is duplicated in its type hierarchy."
Source="System.ServiceModel.Web"
不过,您可以通过创建一个继承自 custom contract resolver 或
DefaultContractResolver
的 CamelCasePropertyNamesContractResolver
来使 Json.NET 表现得像预期的那样,覆盖 CreateProperty()
并添加所需的逻辑:
public class IgnoreDataMemberContractResolver : DefaultContractResolver
{
// As of 7.0.1, Json.NET suggests using a static instance for "stateless" contract resolvers, for performance reasons.
// http://www.newtonsoft.com/json/help/html/ContractResolver.htm
// http://www.newtonsoft.com/json/help/html/M_Newtonsoft_Json_Serialization_DefaultContractResolver__ctor_1.htm
// "Use the parameterless constructor and cache instances of the contract resolver within your application for optimal performance."
// See also https://stackoverflow.com/questions/33557737/does-json-net-cache-types-serialization-information
static IgnoreDataMemberContractResolver instance;
// Explicit static constructor to tell C# compiler not to mark type as beforefieldinit
static IgnoreDataMemberContractResolver() { instance = new IgnoreDataMemberContractResolver(); }
public static IgnoreDataMemberContractResolver Instance { get { return instance; } }
protected override JsonProperty CreateProperty(System.Reflection.MemberInfo member, MemberSerialization memberSerialization)
{
var property = base.CreateProperty(member, memberSerialization);
if (memberSerialization == MemberSerialization.OptIn)
{
// Preserve behavior that [DataMember] supersedes [IgnoreDataMember] when applied in the same type
// but not when appled to a base type.
if (!property.Ignored
&& property.AttributeProvider.GetAttributes(typeof(IgnoreDataMemberAttribute), false).Any()
&& !property.AttributeProvider.GetAttributes(typeof(DataMemberAttribute), true).Any())
{
property.Ignored = true;
}
}
return property;
}
}
然后像这样使用它:
var settings = new JsonSerializerSettings { ContractResolver = IgnoreDataMemberContractResolver.Instance };
var json = JsonConvert.SerializeObject(serverGeneratedObject, settings);
关于c# - IgnoreDataMember 不起作用,但 JsonIgnore 起作用,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/38020614/