【问题标题】:When merging objects using Newtonsoft.Json, how do you ignore empty string values?使用 Newtonsoft.Json 合并对象时,如何忽略空字符串值?
【发布时间】:2015-04-18 07:44:00
【问题描述】:

我有一个在 C# 中定义为类的数据模型。我需要使用 JObject.Merge 合并两个对象,但对于一个特定属性,我需要忽略来自第二个对象的空字符串值,类似于忽略空值的方式。是否有一个现有的属性属性,或者我是否需要自己编写?

void Main()
{
    string json1 = @"{ Foo: ""foo1"", Bar: ""bar1"" }";
    string json2 = @"{ Foo: ""foo2"", Bar: null }";
    string json3 = @"{ Foo: ""foo3"", Bar: """" }";

    var model1 = JObject.Parse(json1);
    var model2 = JObject.Parse(json2);
    model1.Merge(model2);
    model1.Dump();

    model1 = JObject.Parse(json1);
    model2 = JObject.Parse(json3);
    model1.Merge(model2);
    model1.Dump();
}

public class Model
{
    [JsonProperty("foo")]
    public string Foo { get ; set; }

    [JsonProperty("bar", NullValueHandling = NullValueHandling.Ignore)]
    public string Bar { get ; set; }

}

Output (1): Model.Bar = "bar1" 
Output (2): Model.Bar = "";
Desired output of (2): Model.Bar = "bar1"

编辑:好的,我意识到无法应用属性,因为我只需要使用原始 json 字符串作为输入。这主要是因为我的类具有默认值的属性。合并具有空值的类会触发默认值并最终覆盖原始值,这是我不想要的。我需要能够获取类的部分 json 表示并更新原始数据。抱歉,如果从一开始就不清楚。我会更新我最终回答的内容。

【问题讨论】:

  • 您所说的“是否存在此属性”是什么意思? JsonMergeSettings 的房产?还是JObject 本身的属性?

标签: c# json serialization json.net


【解决方案1】:

您可以使用以下扩展方法从要合并的JObject 中删除具有空字符串值的属性:

public static class JsonExtensions
{
    public static void RemovePropertiesByValue(this JToken root, Predicate<JValue> filter)
    {
        var nulls = root.DescendantsAndSelf().OfType<JValue>().Where(v => v.Parent is JProperty && filter(v)).ToList();
        foreach (var value in nulls)
        {
            var parent = (JProperty)value.Parent;
            parent.Remove();
        }
    }

    public static IEnumerable<JToken> DescendantsAndSelf(this JToken node)
    {
        if (node == null)
            return Enumerable.Empty<JToken>();
        var container = node as JContainer;
        if (container != null)
            return container.DescendantsAndSelf();
        else
            return new [] { node };
    }
}

然后像这样使用它:

        model2.RemovePropertiesByValue(v => v.Type == JTokenType.String && string.IsNullOrEmpty((string)v.Value));

请注意,这不会从数组中删除空字符串,因为这会弄乱数组索引,从而导致合并。你也需要那个吗?

【讨论】:

  • 我更喜欢装饰属性,而不是为单个字段创建自定义代码。
  • @DanBailiff - 代码是递归的,它从整个JToken 层次结构中清除空字符串值。此外,此时没有要装饰的属性,您正在使用 JTokens 而不是 POCO。 JsonMergeSettings 中的唯一设置是 MergeArrayHandling,这似乎不相关。
  • 你是对的。通过将 json 转换为对象,然后在发出要合并的 json 时使用“DefaultValueHandling.Ignore”和“DefaultValue(”")”的序列化程序属性,我找到了一种解决方法或“正确方法”。我不知道是否应该更新问题/解决方案或撤回问题?
  • @DanBailiff - 如果您仍然需要帮助,我建议您提出一个新问题,因为它更有可能引起注意。顺便说一句,JsonConvert.PopulateObject 会在这里帮忙吗?
  • @drzaus - JContainer.DescendantsAndSelf() 已经是递归的。但是JValue(和抽象基类JToken)没有实现DescendantsAndSelf()(尽管这样做是有意义的)所以JsonExtensions.DescendantsAndSelf()提供了一个非容器令牌的实现,它只返回自我。
【解决方案2】:

我操纵了 JObject 字典键来按摩特定条目。我觉得很脏,但它有效。我想不出一个“好”的方法来做到这一点。

model1 = JObject.Parse(json1);
model2 = JObject.Parse(json3);
IDictionary<string, JToken> dictionary = model2;
dictionary["Bar"] = string.IsNullOrEmpty((string)dictionary["Bar"])
            ? null
            : dictionary["Bar"];
model1.Merge(model2);

【讨论】:

    猜你喜欢
    • 2016-07-19
    • 2020-02-05
    • 2013-03-19
    • 1970-01-01
    • 1970-01-01
    • 2015-04-12
    • 2019-03-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多