在为循环编写略有不同的内容时,如何停止重复自己?

时间:2017-10-30 10:47:04

标签: c#

我有这些选择和迭代语句。我觉得我做错了什么;我觉得自己重复太多,其中一些可以真正优化。

问题:如何优化多个略有不同的for循环,使其变得更好"?

以下是代码(请注意,周围的功能适用于"每隔0.5秒滴答一次的计时器):

step = 0; //step is a member variable of the surrounding class

timer1_tick(Object obj, EventArg arg)
{
    if (step == 0)
    {
        foreach (HtmlElement elem in browser.Document.GetElementsByTag("a"))
        {
            if (elem.InnerText == "hey")
            {
                elem.InnerText = "blabla";
                break;
            }
        }

        foreach (HtmlElement elem in browser.Document.GetElementsByTag("button"))
        {
            if (elem.InnerText == "clickMe")
            {
                step = 1;
                break;
            }
        }

        return;
    }
    else if (step == 1)
    {
        foreach (HtmlElement elem in browser.Document.GetElementsByTag("div"))
        {
            if (elem.GetAttribute("name") == "something")
            {
                elem.Destroy;
                break;
            }

            if (elem.GetAttribute("name") == "notme")
            {
                elem.Destroy;
                break;
            }

            if (elem.GetAttribute("name") == "notyou")
            {
                elem.Destroy;
                break;
            }

            if (elem.GetAttribute("name") == "notthat")
            {
                elem.Destroy;
                break;
            }

            if (elem.GetAttribute("name") == "theone")
            {
                elem.Destroy;
                break;
            }
        }

        step = 2;
        return;
    }
    else if (step == 2)
    {
        foreach (HtmlElement elem in browser.Document.GetElementsByTag("div"))
        {
            if (elem.InnerHtml == "ClickMeNow")
            {
                elem.InnerHtml = "/Done";
                step = 3;
                break;
            }
        }

        foreach (HtmlElement elem in browser.Document.GetElementsByTag("a"))
        {
            if (elem.InnerHtml == "linkit")
            {
                elem.getAttribute("href") = "www.google.com";
                step = 3;
                break;
            }
        }

        return;
    }
}

2 个答案:

答案 0 :(得分:1)

您可以使用LINQ消除所有这些循环 请注意,您只需使用FirstOrDefault

,而不是摆脱循环

例如,第一个循环:

    foreach (HtmlElement elem in browser.Document.GetElementsByTag("a"))
    {
        if (elem.InnerText == "hey")
        {
            elem.InnerText = "blabla";
            break;
        }
    }

可以替换为:

var elem = browser.Document.GetElementsByTag("a").FirstOrDefault(e => e.InnerText == "hey");
if(elem != null)
{
    elem.InnerText = "blabla";
}

同样,您也可以使用LINQ替换其他循环:

foreach (HtmlElement elem in browser.Document.GetElementsByTag("button"))
{
    if (elem.InnerText == "clickMe")
    {
        step = 1;
        break;
    }
}

可以替换为:

var elem = browser.Document.GetElementsByTag("button").FirstOrDefault(e => e.InnerText == "clickMe");
if(elem != null)
{
    step = 1;
}

这个巨大的循环:

foreach (HtmlElement elem in browser.Document.GetElementsByTag("div"))
{
    if (elem.GetAttribute("name") == "something")
    {
        elem.Destroy;
        break;
    }
    if (elem.GetAttribute("name") == "notme")
    {
        elem.Destroy;
        break;
    }
    if (elem.GetAttribute("name") == "notyou")
    {
        elem.Destroy;
        break;
    }
    if (elem.GetAttribute("name") == "notthat")
    {
        elem.Destroy;
        break;
    }
    if (elem.GetAttribute("name") == "theone")
    {
        elem.Destroy;
        break;
    }
}

可以替换为:

var names = new string[] {"something", "notme", "notyou", "notthat", "theone"};
browser.Document.GetElementsByTag("div").FirstOrDefault(e => names.Contains(e.GetAttribute("name"))?.Destroy;

注意我已使用字符串数组的Contains方法而不是代码中的所有条件。

等等。

另外,我会接受蒂姆的建议,并更改step 1step 2等'使用有意义名称的不同方法。

答案 1 :(得分:1)

我会用这段代码做一些不同的事情:

分解方法

您的timer1_tick方法做了很多事情。通常情况下,我不是任意将代码分解为小方法的粉丝,但我认为它适合这里。而且,转换更合适,而不是外部if... else if...结构。

因此,代码的一般结构如下所示:

public void FirstStep()
{
    //...
}

public void SecondStep()
{
    //...
}

public void ThirdStep()
{
    //...
}

public void timer1_tick()
{
    switch(step)
    {
        case 1:
            FirstStep();
            break;
        case 2:
            SecondStep();
            break;
        case 1:
            ThirdStep();
            break;
    }
}

改进foreach

接下来,让我们解决每个循环问题。在第一步和第三步中,您的结构始终相同:

foreach (HtmlElement elem in browser.Document.GetElementsByTag("<<Selector>>"))
{
    if (elem.InnerText == "<<Selector>>")
    {
        // Do logic...
    }
}

因此,让我们将其提取到另一种方法,并将其用于foreach调用。

public IEnumerable<HtmlElement> GetElementByTagAndContent(string tag, string content)
{
    foreach (HtmlElement elem in browser.Document.GetElementsByTag(tag))
    {
        if (elem.InnerText == content)
            yield return elem
    }
}

并且foreach循环看起来像这样:

foreach(var elem in GetElementByTagAndContent("a", "hey))
{
    // Do Logic...
}

重构第二步

最后,在第二步中,你要做一堆只检查元素名称的if个。此外,他们都采取相同的行动。 switch语句在这里很经典。

switch (elem.GetAttribute("name"))
{
    case "A":
    case "B":        
    case "C":
    case "D":
        elem.Destroy();
        break;
}

最终产品

毕竟,你的代码看起来应该更像这样:

public void FirstStep()
{
    foreach (HtmlElement elem in GetElementByTagAndContent("a", "hey"))
    {
        elem.InnerText = "blabla";
    }

    foreach (HtmlElement elem in GetElementByTagAndContent("button", "clickMe"))
    {
        step = 1;
    }
}

public void SecondStep()
{
    switch (elem.GetAttribute("name"))
    {
        case "A":
        case "B":        
        case "C":
        case "D":
            elem.Destroy();
            break;
    }

    step = 2;
}

public void ThirdStep()
{
    foreach (HtmlElement elem in GetElementByTagAndContent("div", "ClickMeNow"))
    {
        elem.InnerHtml = "/Done";
        step = 3;
    }

    foreach (HtmlElement elem in GetElementByTagAndContent("a", "linkit"))
    {
        elem.getAttribute("href") = "www.google.com";
        step = 3;
    }
}

public void timer1_tick()
{
    switch(step)
    {
        case 1:
            FirstStep();
            break;
         case 2:
            SecondStep();
            break;
        case 1:
            ThirdStep();
            break;
    }
}

public IEnumerable<HtmlElement> GetElementByTagAndContent(string tag, string content)
{
    foreach (HtmlElement elem in browser.Document.GetElementsByTag(tag))
    {
        if (elem.InnerText == content)
            yield return elem
    }
}

希望这有帮助