C# 在为循环编写稍微不同的代码时,如何停止重复自己的操作?

C# 在为循环编写稍微不同的代码时,如何停止重复自己的操作?,c#,C#,我有这些选择和迭代语句。我觉得我做错了什么;我觉得自己重复的太多了,有些地方真的可以优化 问题:如何优化多个稍微不同的循环,使之成为“更好”的循环 以下是代码(请注意,周围的函数适用于每0.5秒“滴答”一次的计时器): 您可以使用LINQ消除所有这些循环。 请注意,您可以简单地使用FirstOrDefault,而不是中断循环: 例如,第一个循环: foreach (HtmlElement elem in browser.Document.GetElementsByTag("a"))

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

问题:如何优化多个稍微不同的循环,使之成为“更好”的循环

以下是代码(请注意,周围的函数适用于每0.5秒“滴答”一次的计时器):


您可以使用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;
}
var names = new string[] {"something", "notme", "notyou", "notthat", "theone"};
browser.Document.GetElementsByTag("div").FirstOrDefault(e => names.Contains(e.GetAttribute("name"))?.Destroy;
这个巨大的循环:

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 elem = browser.Document.GetElementsByTag("button").FirstOrDefault(e => e.InnerText == "clickMe");
if(elem != null)
{
    step = 1;
}
var names = new string[] {"something", "notme", "notyou", "notthat", "theone"};
browser.Document.GetElementsByTag("div").FirstOrDefault(e => names.Contains(e.GetAttribute("name"))?.Destroy;
注意,我使用了字符串数组的Contains方法,而不是代码中的所有条件

等等


此外,我会采纳Tim的建议,将
步骤1
步骤2
等更改为具有有意义名称的不同方法。

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

打破常规 你的
timer1\u tick
方法做了很多事情。通常我不喜欢随意地将代码分解成小方法,但我认为这很适合这里。此外,如果。。。否则,如果…structure,则更适合使用开关

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

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(var elem in GetElementByTagAndContent("a", "hey))
{
    // Do Logic...
}
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
    }
}
改进foreach 接下来,让我们处理for-each循环。在第一步和第三步中,您的结构始终相同:

foreach (HtmlElement elem in browser.Document.GetElementsByTag("<<Selector>>"))
{
    if (elem.InnerText == "<<Selector>>")
    {
        // Do logic...
    }
}
重构第二步 最后,在第二步中,您将执行一系列只检查元素名称的
if
s。而且,它们都做相同的动作。这里的
switch
语句非常经典

switch (elem.GetAttribute("name"))
{
    case "A":
    case "B":        
    case "C":
    case "D":
        elem.Destroy();
        break;
}
最终产品 在所有这些之后,您的代码应该更像这样:

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(var elem in GetElementByTagAndContent("a", "hey))
{
    // Do Logic...
}
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
    }
}
public void FirstStep()
{
foreach(GetElementByTagAndContent(“a”、“hey”)中的HtmlElement元素)
{
elem.InnerText=“blabla”;
}
foreach(GetElementByTagAndContent(“按钮”、“单击我”)中的HtmlElement元素)
{
步骤=1;
}
}
公开作废第二步()
{
开关(elem.GetAttribute(“名称”))
{
案例“A”:
案例“B”:
案例“C”:
案例“D”:
元素Destroy();
打破
}
步骤=2;
}
第三步()的公开无效
{
foreach(GetElementByTagAndContent(“div”、“ClickMeNow”)中的HtmlElement元素)
{
elem.InnerHtml=“/Done”;
步骤=3;
}
foreach(GetElementByTagAndContent(“a”、“linkit”)中的HtmlElement元素)
{
elem.getAttribute(“href”)=“www.google.com”;
步骤=3;
}
}
公共无效计时器1_tick()
{
开关(步骤)
{
案例1:
第一步();
打破
案例2:
第二步();
打破
案例1:
第三步();
打破
}
}
公共IEnumerable GetElementByTagAndContent(字符串标记,字符串内容)
{
foreach(browser.Document.GetElementsByTag(标记))中的HtmlElement元素
{
if(elem.InnerText==内容)
收益率要素
}
}

希望这有帮助

请格式化代码,它不可读this@EpicKip怎样?我只是直接写了出来,结果是这样的。顺便说一句,我是新来的:)@sdsadasd
你会觉得有什么不对劲
很主观。正如Manfred所说,通过缩进代码,您可以使其可读。^重构的第一步应该是为每个步骤提取具有有意义名称的方法。步骤本身应该是一个
enum
(具有有意义的名称)而不是
int
。您可以通过在foreach中进行过滤(因此没有if)使其变得更小,例如:
foreach(browser.Document.GetElementsByTag(“a”)。其中(a=>a.InnerText==“Hey”)
您的最终语句不正确,无法写入null条件运算符返回的条件访问表达式-它只能用于读取或删除querying@LordWilmore我不确定你指的是什么陈述,因为你发表评论时我正在编辑答案。你能说得更具体一点吗?关于C#6中空条件运算符的评论完全正确。我本来打算在午餐时开始键入答案,但这几乎涵盖了它-将方法分解为关键的离散元素是关键