【问题标题】:How can I avoid catching an Exception using an if?如何避免使用 if 捕获异常?
【发布时间】:2021-03-18 15:26:11
【问题描述】:

我正在抓取一个网页,直到现在我正在使用 try/catch 捕获一个 ArgumentNullException。但是,我想将逻辑更改为使用if。我的尝试在下面。

if (document.DocumentNode.SelectNodes("//td")
        .Where(x => x.Attributes["title"].Value.Contains("Log.html")).Any() is true) { 

        HtmlNode[] nodes = document.DocumentNode.SelectNodes("//td")
           .Where(x => x.Attributes["title"].Value.Contains("Log.html")).ToArray();
        if (nodes.Length > 1) {
           nodes = nodes.Where((source, index) => index != 1).ToArray();
        }
     [..........]
     } else {
        LogException("Item is null", taskId, buildId);
     }

但是就行了:

if (document.DocumentNode.SelectNodes("//td") .Where(x => x.Attributes["title"].Value.Contains("Log.html")).Any() 为真)

我仍然收到ArgumentNullException。我应该怎么写呢?

【问题讨论】:

  • 首先你不应该抓住ArgumentNullException。相反,您应该首先避免它。除此之外,异常究竟发生在哪里?这里哪个变量为空?
  • 您可以使用when in a catch 语句仅在条件为真时捕获异常。目前还不清楚你想要什么。您发布的内容不应引发此类异常除非 Value 为空。 is true 没有意义,因为 Any 总是返回一个布尔值。 实际异常是什么?如果Value 为空,捕获异常将无济于事
  • 您可以使用 .SelectNodes.Any(x=>...) 来缩短表达式,但更好的选择是使用适当的 XPath 表达式://td[contains(@title,'Log.html')]
  • 抓取网页时,有时Log.html 会丢失,因此Value 为空并抛出此异常。我之前可以使用try/catch 绕过它,但我认为这不是一个好习惯,至少在这种情况下是这样。因此,我一直在尝试使用if,但我不知道怎么做。
  • 谢谢@PanagiotisKanavos,我会试试的。

标签: c# web-scraping html-agility-pack


【解决方案1】:

您也可以使用 XPath 表达式来检查属性内容:

var logs=document.DocumentNode
                 .SelectNodes("//td[contains(@title,'Log.html')]")
                 .ToArray();
if (logs.Length==0)
{
    LogException("Item is null", taskId, buildId);
} 
else if (logs.Length>1)
{
    logs=logs[1..];
}

C#8 中的新范围语法允许替换

nodes.Where((source, index) => index != 1).ToArray();

只有

logs=logs[1..];

【讨论】:

    【解决方案2】:

    为什么不

     .Where(x => {
        if (x.Attributes["title"] != null) { 
           return x.Attributes["title"].Value.Contains("Log.html")).Any();
        }
        else { 
           return false;
        }
      })
    

    【讨论】:

    • 这还能编译吗? x.Attributes["title"] 返回一个 bool so x.Attributes["title"].Value.Contains`` 将无法编译,或者它不是布尔值,在这种情况下x.Attributes["title"] 将失败
    • 对不起,对于很多 JS 和 C++ 来说,if (null) 被简单地处理为假......对不起,C# 是如此有限。
    • 或者更短一点的=> x.Attributes["title"]?.Value.Contains("Log.html").Any() == true;
    • @HimBromBeere 是的,你为什么不把你的评论变成一个遮阳篷?
    • @rioki 这种技术只在上个世纪使用过,当时 C 还没有真正的 boolean 类型。自 C99 以来,这是不受欢迎的。 C++ 的良好实践也强烈不鼓励这种做法,因为它会导致意想不到的错误。出于同样的原因,JavaScript 使用===。这不是 C# 限制。
    【解决方案3】:

    一种方法可能是:

    var nodes = document.DocumentNode.SelectNodes("//td");
    if (nodes.Any())
    {
        var logs = nodes.Where(x => x.Attributes["title"].Value.Contains("Log.html"));
        if(logs.Any())
        {
            var filterLogs = logs.Where((source, index) => index != 1).ToArray();
        }
        
    }
    

    另一个选项取决于您的 C# 版本,它使用可选链 null Null Conditional operator

    var result = document.DocumentNode?.SelectNodes("//td")?
        .Where(x => x.Attributes["title"].Value?.Contains("Log.html"))
    

    【讨论】:

    • Null 条件运算符确实改变了生活。谢谢!
    • 我不喜欢这个解决方案,因为它不止一次地评估延迟枚举。评估一个延迟的可枚举对象的成本可能很高,而且执行两次有时(不是在这种情况下)会产生不一致的结果。
    猜你喜欢
    • 1970-01-01
    • 2023-01-03
    • 1970-01-01
    • 2011-03-05
    • 1970-01-01
    • 2017-02-10
    • 1970-01-01
    • 2016-03-21
    • 2010-09-29
    相关资源
    最近更新 更多