【问题标题】:How can I shorten beautifully this C# code?我怎样才能漂亮地缩短这个 C# 代码?
【发布时间】:2019-03-02 22:05:45
【问题描述】:

我想消除一些重复的代码。谁能让这段代码更短更好?

switch (now.site)
{

    case item.SITE.AMAZON:
        try
        {
            price = driver.FindElement(By.XPath("//*[@id=\"priceblock_ourprice\"]")).Text;
            fetched = true;
        }
        catch
        {
            try
            {
                price = driver.FindElement(By.XPath("//*[@id=\"priceblock_dealprice\"]")).Text;
                fetched = true;
            }
            catch
            {
                fetched = false;
            }
        }
        break;
    case item.SITE.ALI:
        try
        {
            price = driver.FindElement(By.XPath("//*[@id=\"j-sku-discount-price\"]")).Text;
            fetched = true;
        }
        catch
        {
            try
            {
                price = driver.FindElement(By.XPath("//*[@id=\"j-sku-price\"]")).Text;
                fetched = true;
            }
            catch
            {
                fetched = false;
            }
        }
        break;
    }
}

【问题讨论】:

  • 请不要使用异常编码。例外是针对特殊情况的。如果您尝试在普通代码中使用它们,那么它们也可以称为System.Ordinary
  • 是否有机会获得minimal reproducible example,以便我们提供干净的解决方案?我至少应该能够复制、粘贴和编译您的代码。
  • 真正的网上冲浪会导致许多例外情况。如果 C# selenium 知道元素存在或可点击,我同意你的看法。
  • 然后捕获抛出的特定异常,而不是每个异常。这是一个不好的做法。然后抽象出代码,以便您只处理一次。
  • 好的,感谢它找到特定异常的权利

标签: c# oop refactoring


【解决方案1】:

您可以创建可用路径字符串的字典。我不知道site 的类型是什么。我假设string

private static Dictionary<string, string[]> pricePaths = new Dictionary<string, string[]> {
   [item.SITE.AMAZON] = new string[] { "//*[@id=\"priceblock_ourprice\"]",
                                       "//*[@id=\"priceblock_dealprice\"]" },
   [item.SITE.ALI] = new string[] { "//*[@id=\"j-sku-discount-price\"]",
                                    "//*[@id=\"j-sku-price\"]" },
};

有了这个,你可以写一个更通用的逻辑。

bool fetched = false;
if (pricePaths.TryGetValue(now.site, out string[] paths)) {
    foreach (string path in paths) {
        try {
            price = driver.FindElement(By.XPath(path)).Text;
            fetched = true;
            break;
        } catch {
        }
    }
}

它允许您轻松添加新网站。这些站点可以有任意数量的备用路径。

【讨论】:

  • 太棒了!非常感谢..!!
【解决方案2】:

看来您确实在尝试获取十进制值。让我们使用这个假设并创建一个返回decimal? 的方法来指示成功(即一个值)或失败(即null)。

public static class Ex
{
    public static decimal? FindDecimalMaybe(this IWebDriver driver, string path)
    {
        try
        {
            if (decimal.TryParse(driver.FindElement(By.XPath(path)).Text, out decimal result))
            {
                return result;
            }
        }
        catch { } // I hate this, but there doesn't seem to be a choice
        return null;
    }
}

此方法的目的是隐藏 Selenium 库在代码中出现异常这一令人不快的事实。

我还将它创建为一个扩展方法,以便对 driver.FindElement 的调用被替换为看起来很熟悉的东西 - driver.FindDecimalMaybe

现在我用字典和奥利弗一样的方法:

private static Dictionary<string, string[]> __pricePaths = new Dictionary<string, string[]>
{
    { item.SITE.AMAZON, new [] { "//*[@id=\"priceblock_ourprice\"]", "//*[@id=\"priceblock_dealprice\"]" } },
    { item.SITE.ALI, new [] { "//*[@id=\"j-sku-discount-price\"]", "//*[@id=\"j-sku-price\"]" } },
};

现在取出值是微不足道的:

decimal? price =
    __pricePaths[now.site]
        .Select(path => driver.FindDecimalMaybe(path))
        .Where(x => x.HasValue)
        .FirstOrDefault();

如果price 变量有值则成功,但如果是null 则调用不成功。

【讨论】:

    【解决方案3】:

    这里有一些关于如何美化代码的建议 -

    1. 为所有 XPath 查询声明常量。
    2. 在 switch 语句之外声明一个变量,以根据您的 case 语句捕获价格值。
    3. 使用一个 try catch 语句创建一个函数,该语句接受 2 个 xPath 字符串和一个用于 Price 的 out 参数,并返回一个布尔值以指示查询是否成功。
    4. 从每种情况下删除 try catch 并调用该函数,从常量集中传递正确的 xPath 字符串。

      const string priceblock_ourprice = "//*[@id=\"priceblock_ourprice\"]";
      const string priceblock_dealprice = "//*[@id=\"priceblock_dealprice\"]";
      const string j_sku_discount_price = "//*[@id=\"j-sku-discount-price\"]";
      const string j_sku_price = "//*[@id=\"j-sku-price\"]";
      
      public void YourPrimaryFunction
      {  
          decimal price;  
          switch (now.site)  
          {  
              case item.SITE.AMAZON:  
                  fetched = FetchPrice(priceblock_ourprice, priceblock_dealprice, out price);
                  break;  
              case item.SITE.ALI:  
                  fetched = FetchPrice(j_sku_discount_price, j_sku_price, out price);
                  break;
          }
      }
      
      private bool FetchPrice(string xPathPrim, string xPathFallBack, decimal out price)
      {
          try
          {
              price = driver.FindElement(By.XPath(xPathPrim)).Text;
              return true;
          }
          catch
          {
              try
              {
                  price = driver.FindElement(By.XPath(xPathFallBack)).Text;
                  return true;
              }
              catch
              {
                  return false;
              }
          }
      }
      

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-03-13
      • 1970-01-01
      • 2020-10-08
      • 2011-06-03
      • 1970-01-01
      相关资源
      最近更新 更多