我遇到了一个奇怪的情况,其中 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/

10-10 05:19