【问题标题】:How to serialize all but a specific property in one specific serialization如何在一个特定序列化中序列化除特定属性之外的所有属性
【发布时间】:2014-09-30 22:22:16
【问题描述】:

我有一个看起来像这样的对象(显然是简化的)

public class Person {
  public string Name { get; set; }
  public int Age { get; set; }
  public string ETag { get { return ... } }
}

我希望 ETag 成为省略 ETag 属性的对象的 json 序列化的哈希(以防止递归循环)。但是,我不能只使用 [JsonIgnore] 属性,因为在其他时候我希望能够对整个事物进行 json 序列化。

所以我想要的是这样的

public string ETag { get {
   return Hash(JsonConvert.Serialize(this, p => p.Ignore(x=>x.ETag) ));
}}

不幸的是,这不是一个存在的 API。我将如何实现类似的目标?

【问题讨论】:

  • 不是最漂亮的解决方案,但我刚刚创建了一个类似的对象,可以从省略字段的主对象构造,并在需要时对其进行序列化。
  • @BradleyDotNET 是的,使用 automapper 和其他东西有很多方法可以做到这一点,但维护起来很麻烦,因为我希望这个对象会发生很大变化

标签: c# json serialization json.net


【解决方案1】:

您可以使用自定义IContractResolver 以编程方式忽略对象的属性。所以我认为我将采取的方法是创建一个简单的解析器,它可以专门忽略单个类型上的单个属性(显然,如果需要,您可以扩展它),然后创建一个可以使用该解析器序列化的辅助方法。使用 ETag 属性中的辅助方法,一切顺利。

这是解析器的代码:

class IgnorePropertyResolver : DefaultContractResolver
{
    Type targetType;
    string targetPropertyName;

    public IgnorePropertyResolver(Type targetType, string propertyName)
    {
        this.targetType = targetType;
        this.targetPropertyName = propertyName;
    }

    protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
    {
        IList<JsonProperty> props = base.CreateProperties(type, memberSerialization);
        if (targetType == type)
        {
            props = props.Where(p => p.PropertyName != targetPropertyName).ToList();
        }
        return props;
    }
}

这是辅助方法(我还在那里扔了一个哈希辅助方法,因为你没有在你的问题中定义它):

static class JsonHelper
{
    public static string Serialize(object target, string propertyToIgnore)
    {
        JsonSerializerSettings settings = new JsonSerializerSettings();
        settings.ContractResolver = new IgnorePropertyResolver(target.GetType(), propertyToIgnore);
        return JsonConvert.SerializeObject(target, settings);
    }

    public static string Hash(string json)
    {
        using (var sha = new SHA1Managed())
        {
            return Convert.ToBase64String(sha.ComputeHash(Encoding.UTF8.GetBytes(json)));
        }
    }
}

最后,这是一个工作演示:

class Program
{
    static void Main(string[] args)
    {
        Person p = new Person { Name = "Joe", Age = 26 };
        Console.WriteLine("Etag = " + p.ETag);
        Console.WriteLine();
        Console.WriteLine(JsonConvert.SerializeObject(p, Formatting.Indented));
    }
}

public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
    public string ETag
    {
        get { return JsonHelper.Hash(JsonHelper.Serialize(this, "ETag")); }
    }
}

输出:

Etag = T99YVDlrbZ66YL2u5MYjyIyO4Qk=

{
  "Name": "Joe",
  "Age": 26,
  "ETag": "T99YVDlrbZ66YL2u5MYjyIyO4Qk="
}

小提琴:https://dotnetfiddle.net/YgVJ4K

【讨论】:

  • 如果你想避免字符串类型的属性名称,你可以使用表达式树解析来保持它的强类型。我在这里更新了 Brian 的示例:dotnetfiddle.net/G5u8NJ
  • 太棒了。非常感谢!我不介意在这种情况下进行字符串输入,因为在这种情况下,所有内容都是被命名的属性实例的内部
【解决方案2】:

它并不漂亮,但您可以在 JSON 序列化之后使用字符串替换。您可以将 ETag 设置为标记值,​​以便在序列化后可以替换/删除该元素。

【讨论】:

  • 请给代码?这样做仍然会调用 Etag 导致递归循环。我知道使用 JsonSerializerSettings 有更好的方法,我只是不知道具体方法
猜你喜欢
  • 1970-01-01
  • 2012-11-19
  • 2017-07-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多