我有这些选择和迭代语句。我觉得我做错了什么;我觉得自己重复太多,其中一些可以真正优化。
问题:如何优化多个略有不同的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;
}
}
答案 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 1
,step 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 (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
}
}
希望这有帮助