【问题标题】:Eliminate IF checks in LINQ deep structure消除 LINQ 深层结构中的 IF 检查
【发布时间】:2014-08-13 17:20:36
【问题描述】:

我想使用 XDocument 访问 XML 文档中的一些深层结构。

为了避免 NULL 异常,所以我有很多这样的 IF 检查

if(doc.Root.Element("E1") != null)
{
    if(doc.Root.Element("E1").Element("E2") != null)
    { 
        if(doc.Root.Element("E1")
                   .Element("E2")
                   .SingleOrDefault(e => e.Attribute("id") != null && 
                                         e.Attribute("id").Equals("ABC")) != null)
        {
             var n = doc.Root
                        .Element("E1")
                        .Element("E2")
                        .SingleOrDefault(e => e.Attribute("id") != null && 
                                              e.Attribute("id").Equals("ABC"))
                        .Attribute("name").Value;
        }
    }
}

实际结构要深得多。我能以某种方式消除这些 NULL 检查吗?

【问题讨论】:

标签: c# xml linq if-statement null


【解决方案1】:

您可以创建一个简单的扩展方法,该方法能够将投影应用于可能为 null 的值,该值传播 null 值而不是引发异常:(请注意,不同的人喜欢为此操作使用不同的名称;请随意调用该方法对你来说最有意义。)

public static TResult Use<TSource, TResult>(
    this TSource obj, Func<TSource, TResult> selector)
    where TSource : class
    where TResult : class
{
    return obj == null ? null : selector(obj);
}

有了这个,你的代码可以被压缩成以下:

var name = doc.Root.Element("E1")
        .Use(element => element.Elements("E2"))
        .Use(elements => elements.SingleOrDefault(
            element => element.Attribute("id")
                .Use(att => att.Value) == "ABC"))
        .Use(element => element.Attribute("name").Value);

【讨论】:

  • 个人 - 我宁愿看到空检查而不是这个。
  • @Mike 非常欢迎您在自己的代码中这样做。
  • 我会的!感谢您给予我的许可!
【解决方案2】:

您不需要任何检查。您可以将属性转换为string,然后使用== 而不是Equals 检查相等性。

对于元素,您可以使用XPath 而不是像Root.Element("Foo").Element("Bar") 等那样单独选择它们。然后只检查XPath 查询的结果。至少需要less检查...

另外值得注意的是,在C# 6 中会有一个Null propagating operator,它允许您安全地访问对象的成员,那么您将不需要任何这些检查..

【讨论】:

  • 那只是去掉了一些检查,你还有所有的元素检查
  • 不太确定你为什么会被否决 - 一个合理的答案......为未来提供了一些很好的信息。这让你不想在这里帮助任何人。
【解决方案3】:

你可以这样做:

            var n = doc.Elements("E1").DefaultIfEmpty()
                    .Elements("E2").DefaultIfEmpty()
                    .FirstOrDefault(e => e!= null && e.Attribute("id") != null && e.Attribute("id").Equals("ABC"));

        if (n != null) {
            string s = n.Attribute("name").Value;
        }

【讨论】:

  • 如果没有 E1 或 E2 元素,这将抛出 NRE。 Elements 也不是调用第一个 DefaultIfEmpty 的结果的有效方法。
  • 它不会抛出 NRE,因为我设置了 DefaultIfEmpty(),试试这个代码。
  • 如果没有元素,你认为DefaultIfEmpty 会返回什么?它将返回具有单个 null 值的项目序列。如果您从该序列中获得第一个项目,那么您将拥有null,它会抛出一个 NRE。为什么不试试代码。最重要的是,它在语义上是不同的,因为你没有得到第一个元素,你得到的是一系列元素,这不是 OP 的代码正在做的事情。
  • 集合有一个空元素,但我检查它是否不同于 FirstOrDefaultPart(e => e != null && ...
  • 如果您删除了 DefaultIfEmtpy 调用,您可以删除该空检查,因为永远不会有任何空值。但是你仍然会遇到不只是获取第一个元素,而是获取所有元素的问题。
猜你喜欢
  • 2018-11-02
  • 1970-01-01
  • 1970-01-01
  • 2022-06-10
  • 1970-01-01
  • 2021-06-15
  • 1970-01-01
  • 1970-01-01
  • 2019-06-27
相关资源
最近更新 更多