繁体   English   中英

序列化属性,但不要在 Json.Net 中反序列化属性

[英]Serialize Property, but Do Not Deserialize Property in Json.Net

虽然我找到了很多方法来反序列化特定属性,同时防止它们序列化,但我正在寻找相反的行为。

我发现很多问题都在问相反的问题:

使属性反序列化但不使用 json.net 序列化

我可以指示 Json.NET 反序列化但不序列化特定属性吗?

JSON.Net - 仅在序列化时使用 JsonIgnoreAttribute(但在反序列化时不使用)

如何序列化特定属性,但防止它反序列化回 POCO? 是否有我可以用来装饰特定属性的属性?

基本上,我正在寻找与 ShouldSerialize* 方法等效的反序列化方法。

我知道我可以编写自定义转换器,但这似乎有点矫枉过正。

编辑:

这里有更多的上下文。 这背后的原因是我的班级看起来像:

public class Address : IAddress
{
    /// <summary>
    /// Gets or sets the two character country code
    /// </summary>
    [JsonProperty("countryCode")]
    [Required]
    public string CountryCode { get; set; }

    /// <summary>
    /// Gets or sets the country code, and province or state code delimited by a vertical pipe: <c>US|MI</c>
    /// </summary>
    [JsonProperty("countryProvinceState")]
    public string CountryProvinceState
    {
        get
        {
            return string.Format("{0}|{1}", this.CountryCode, this.ProvinceState);
        }
        set
        {
            if (!string.IsNullOrWhiteSpace(value) && value.Contains("|"))
            {
                string[] valueParts = value.Split('|');
                if (valueParts.Length == 2)
                {
                    this.CountryCode = valueParts[0];
                    this.ProvinceState = valueParts[1];
                }
            }
        }
    }

    [JsonProperty("provinceState")]
    [Required]
    public string ProvinceState { get; set; }
}

我需要请求的CountryProvinceState属性,但我不希望它反序列化并触发 setter 逻辑。

最简单的方法是将真实属性标记为[JsonIgnore]并创建一个仅获取代理属性:

    /// <summary>
    /// Gets or sets the country code, and province or state code delimited by a vertical pipe: <c>US|MI</c>
    /// </summary>
    [JsonIgnore]
    public string CountryProvinceState
    {
        get
        {
            return string.Format("{0}|{1}", this.CountryCode, this.ProvinceState);
        }
        set
        {
            if (!string.IsNullOrWhiteSpace(value) && value.Contains("|"))
            {
                string[] valueParts = value.Split('|');
                if (valueParts.Length == 2)
                {
                    this.CountryCode = valueParts[0];
                    this.ProvinceState = valueParts[1];
                }
            }
        }
    }

    [JsonProperty("countryProvinceState")]
    string ReadCountryProvinceState
    {
        get { return CountryProvinceState; } 
    }

如果您愿意,代理属性可以是私有的。

更新

如果您必须对许多类中的许多属性执行此操作,则创建自己的ContractResolver来检查自定义属性可能会更容易。 如果找到,该属性将表示该属性是仅获取的:

[System.AttributeUsage(System.AttributeTargets.Property, AllowMultiple = false)]
public class GetOnlyJsonPropertyAttribute : Attribute
{
}

public class GetOnlyContractResolver : DefaultContractResolver
{
    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
    {
        var property = base.CreateProperty(member, memberSerialization);
        if (property != null && property.Writable)
        {
            var attributes = property.AttributeProvider.GetAttributes(typeof(GetOnlyJsonPropertyAttribute), true);
            if (attributes != null && attributes.Count > 0)
                property.Writable = false;
        }
        return property;
    }
}

然后像这样使用它:

[JsonProperty("countryProvinceState")]
[GetOnlyJsonProperty]
public string CountryProvinceState { get; set; }

进而:

        var settings = new JsonSerializerSettings { ContractResolver = new GetOnlyContractResolver() };

        var address = JsonConvert.DeserializeObject<Address>(jsonString, settings);

在您的问题中,您有一个简单的字符串属性。 但是当你有一个对象时,它会更复杂一些。 .Writeable = false的解决方案将不起作用,因为反序列化将转到对象的属性。 考虑以下代码:

public class Constants
{
    public Address Headquarters { get; set; }

    public static Constants Instance = new Constants
    {
        Headquarters = new Address { Street = "Baker Street" }
    };
}
public class Address
{
    public string Street { get; set; }
}

public class Data
{
    [GetOnlyJsonProperty]
    // we want this to be included in the response, but not deserialized back
    public Address HqAddress { get { return Constants.Instance.Headquarters; } }
}

// somewhere in your code:
var data = JsonConvert.DeserializeObject<Data>("{'HqAddress':{'Street':'Liverpool Street'}}", settings);

现在 JSON 仍然不会尝试为HqAddress属性创建新的Addreess对象,因为它只有 getter。 但是随后(即使.Writeable == false )它更深入并反序列化Street属性,将“Liverpool Street”设置为Constants.Instance.Heqdquarters对象,覆盖应用程序常量中的数据。

解决方案是:在 Newtonsoft.JSON 的新版本中(我在 v10 中尝试过),有一个新属性ShouldDeserialize 所以解析器应该是:

public class GetOnlyContractResolver : DefaultContractResolver
    {
        protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
        {
            var property = base.CreateProperty(member, memberSerialization);
            if (property != null) // Change here (1)
            {
                var attributes = property.AttributeProvider.GetAttributes(typeof(GetOnlyJsonPropertyAttribute), true);
                if (attributes != null && attributes.Count > 0)
                    property.ShouldDeserialize = (a) => false;  // Change here (2)
            }
            return property;
        }
    }

(1) 我删除了&& property.Writeable的条件,所以它处理HqAddress并跳过完整树的反序列化。 (2) ShouldDeserialize是一个谓词,调用每个对象进行反序列化。 因此,您可以有条件地仅跳过某些属性。 但在这里,我让它变得简单。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM