【问题标题】:C# foreach loop outer string not updating as normalC# foreach 循环外部字符串未正常更新
【发布时间】:2015-07-13 22:04:29
【问题描述】:

我知道最好用适当的类编写 Xml 文档,但我时间紧迫,想要快速获得结果。

我尝试将 xml 文件写入字符串,然后将其保存为 xml 文件。 结果不正确,因为字符串每次都只获取foreach循环的最后一个值。

我搜了一下问题,发现需要在foreach循环里面初始化字符串,但是没看懂概念,也不知道具体在哪里。

我应该在我的代码中修改什么?

string siteMap = "<? xml version = \"1.0\" encoding = \"UTF-8\" ?>";

List<string> Niveau1Titles = getNiveau1Titles(aux1);
List<List<Couple>> Niveau2Titles = getNiveau2Titles(aux1);

int i = 0;
foreach (var n2 in Niveau2Titles)
{
    siteMap += "<Niveau_1 Title = \"" + Niveau1Titles[i] + "\" >";
    foreach (var n22 in n2)
    {
        siteMap += "<Niveau_2 Title = \"" + n22.Title + "\" Link = \"" + n22.Link + "\" >";
        List<Couple> Niveau3Titles = new List<Couple>();
        Niveau3Titles = getNiveau3Titles(n22.Link);
        foreach(var n3 in Niveau3Titles)
        {
            siteMap += "<Niveau_3 Title = \"" + n3.Title + "\" Link = \"" + n3.Link + "\" />";
        }
        siteMap += "</Niveau_2>";

    }
    siteMap += "</Niveau_1>";
    i++;
}


Console.WriteLine(siteMap);

【问题讨论】:

  • The result is not correct, because the string is getting only the last value of the foreach loop every time 您的代码中有 3 个foreach,是哪一个导致了问题?
  • 乍一看代码没有任何问题。它应该按预期工作。你能给我们展示一个给你意想不到的结果的例子吗?另外,您是否验证过 getNiveauXTitles 函数是否都为您提供了正确的数据?
  • 我没有看到您的代码在哪里创建了单个根元素。附言我真的不明白,不使用正确的 XML API 怎么能节省你的时间。
  • 内部的(第三个 foreach)正在制造问题。当我使用 Console.WriteLine() 时,结果是正确的。
  • @DeepBlue,更新您当前和所需的输出?并且还包括所有 getNiveauTitles 函数 + NiveauXTitles 类。我们总是需要所有相关信息。

标签: c# xml foreach


【解决方案1】:

花 5 分钟时间来确保这是使用 LINQ to XML 生成的似乎并不难:

var result =
    new XDocument(
        new XDeclaration("1.0", "UTF-8", "yes"),
        new XElement(
            "sitemap",
            Niveau2Titles.Zip(Niveau1Titles, (n2, n1) =>
                new XElement(
                    "Niveau_1",
                    new XAttribute("Title", n1),
                    n2.Select(n22 =>
                        new XElement(
                            "Niveau_2",
                            new XAttribute("Title", n22.Title),
                            new XAttribute("Link", n22.Link),
                            getNiveau3Titles(n22.Link).Select(n3 =>
                                new XElement(
                                    "Niveau_3",
                                    new XAttribute("Title", n3.Title),
                                    new XAttribute("Link", n3.Link)))))))));

【讨论】:

    【解决方案2】:

    我认为代码运行正常。您的 xml 中有多个根元素。您需要添加一个根。此外,您在 xml 标识行中有一个额外的空间。试试下面的代码。

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    namespace ConsoleApplication1
    {
        class Program
        {
            static void Main(string[] args)
            {
                string aux1 = "";
                //remove extra space
                string siteMap = "<?xml version = \"1.0\" encoding = \"UTF-8\" ?>";
                siteMap += "<Root>";
    
                List<string> Niveau1Titles = getNiveau1Titles(aux1);
                List<List<Couple>> Niveau2Titles = getNiveau2Titles(aux1);
    
                int i = 0;
                foreach (var n2 in Niveau2Titles)
                {
                    siteMap += "<Niveau_1 Title = \"" + Niveau1Titles[i] + "\" >";
                    foreach (var n22 in n2)
                    {
                        siteMap += "<Niveau_2 Title = \"" + n22.Title + "\" Link = \"" + n22.Link + "\" >";
                        List<Couple> Niveau3Titles = new List<Couple>();
                        Niveau3Titles = getNiveau3Titles(n22.Link);
                        foreach (var n3 in Niveau3Titles)
                        {
                            siteMap += "<Niveau_3 Title = \"" + n3.Title + "\" Link = \"" + n3.Link + "\" />";
                        }
                        siteMap += "</Niveau_2>";
    
                    }
                    siteMap += "</Niveau_1>";
                    i++;
                }
                siteMap += "</Root>";
    
    
                Console.WriteLine(siteMap);
                Console.ReadLine();
            }
            static List<string> getNiveau1Titles(string aux1)
            {
                return new List<string> { "aaa", "aab", "aac", "aad" };
            }
            static List<List<Couple>> getNiveau2Titles(string aux1)
            {
                return new List<List<Couple>>() { 
                      new List<Couple>() {new Couple() { Title = "T11", Link =  "L11"}, new Couple() { Title = "T12", Link =  "L12"}, new Couple() { Title = "T13", Link =  "L13"} },
                      new List<Couple>() {new Couple() { Title = "T21", Link =  "L21"}, new Couple() { Title = "T22", Link =  "L22"}, new Couple() { Title = "T23", Link =  "L23"} },
                      new List<Couple>() {new Couple() { Title = "T31", Link =  "L31"}, new Couple() { Title = "T32", Link =  "L32"}, new Couple() { Title = "T33", Link =  "L33"} },
                      new List<Couple>() {new Couple() { Title = "T41", Link =  "L41"}, new Couple() { Title = "T42", Link =  "L42"}, new Couple() { Title = "T43", Link =  "L43"} }
                };
            }
            static List<Couple> getNiveau3Titles(string aux1)
            {
                return new List<Couple>() { new Couple() { Title = "T100", Link = "L100" }, new Couple() { Title = "T101", Link = "L101" }, new Couple() { Title = "T102", Link = "L102" } };
            }
    
        }
        public class Couple
        {
            public string Title { get; set; }
            public string Link { get; set; }
        }
    
    }
    ​
    

    这是xml结果

    <?xml version = "1.0" encoding = "UTF-8" ?>
    <Root>
      <Niveau_1 Title = "aaa" >
        <Niveau_2 Title = "T11" Link = "L11" >
          <Niveau_3 Title = "T100" Link = "L100" />
          <Niveau_3 Title = "T101" Link = "L101" />
          <Niveau_3 Title = "T102" Link = "L102" />
        </Niveau_2>
        <Niveau_2 Title = "T12" Link = "L12" >
          <Niveau_3 Title = "T100" Link = "L100" />
          <Niveau_3 Title = "T101" Link = "L101" />
          <Niveau_3 Title = "T102" Link = "L102" />
        </Niveau_2>
        <Niveau_2 Title = "T13" Link = "L13" >
          <Niveau_3 Title = "T100" Link = "L100" />
          <Niveau_3 Title = "T101" Link = "L101" />
          <Niveau_3 Title = "T102" Link = "L102" />
        </Niveau_2>
      </Niveau_1>
      <Niveau_1 Title = "aab" >
        <Niveau_2 Title = "T21" Link = "L21" >
          <Niveau_3 Title = "T100" Link = "L100" />
          <Niveau_3 Title = "T101" Link = "L101" />
          <Niveau_3 Title = "T102" Link = "L102" />
        </Niveau_2>
        <Niveau_2 Title = "T22" Link = "L22" >
          <Niveau_3 Title = "T100" Link = "L100" />
          <Niveau_3 Title = "T101" Link = "L101" />
          <Niveau_3 Title = "T102" Link = "L102" />
        </Niveau_2>
        <Niveau_2 Title = "T23" Link = "L23" >
          <Niveau_3 Title = "T100" Link = "L100" />
          <Niveau_3 Title = "T101" Link = "L101" />
          <Niveau_3 Title = "T102" Link = "L102" />
        </Niveau_2>
      </Niveau_1>
      <Niveau_1 Title = "aac" >
        <Niveau_2 Title = "T31" Link = "L31" >
          <Niveau_3 Title = "T100" Link = "L100" />
          <Niveau_3 Title = "T101" Link = "L101" />
          <Niveau_3 Title = "T102" Link = "L102" />
        </Niveau_2>
        <Niveau_2 Title = "T32" Link = "L32" >
          <Niveau_3 Title = "T100" Link = "L100" />
          <Niveau_3 Title = "T101" Link = "L101" />
          <Niveau_3 Title = "T102" Link = "L102" />
        </Niveau_2>
        <Niveau_2 Title = "T33" Link = "L33" >
          <Niveau_3 Title = "T100" Link = "L100" />
          <Niveau_3 Title = "T101" Link = "L101" />
          <Niveau_3 Title = "T102" Link = "L102" />
        </Niveau_2>
      </Niveau_1>
      <Niveau_1 Title = "aad" >
        <Niveau_2 Title = "T41" Link = "L41" >
          <Niveau_3 Title = "T100" Link = "L100" />
          <Niveau_3 Title = "T101" Link = "L101" />
          <Niveau_3 Title = "T102" Link = "L102" />
        </Niveau_2>
        <Niveau_2 Title = "T42" Link = "L42" >
          <Niveau_3 Title = "T100" Link = "L100" />
          <Niveau_3 Title = "T101" Link = "L101" />
          <Niveau_3 Title = "T102" Link = "L102" />
        </Niveau_2>
        <Niveau_2 Title = "T43" Link = "L43" >
          <Niveau_3 Title = "T100" Link = "L100" />
          <Niveau_3 Title = "T101" Link = "L101" />
          <Niveau_3 Title = "T102" Link = "L102" />
        </Niveau_2>
      </Niveau_1>
    </Root>​
    

    【讨论】:

    • 他们说一张图片值 1000 字。
    【解决方案3】:

    在 C# 中使用 lambda 表达式或匿名方法时,我们必须警惕 访问修改闭包 的陷阱。例如:

    foreach (var s in strings)
    {
       query = query.Where(i => i.Prop == s); // access to modified closure
       ...
    }
    

    由于修改了闭包,上面的代码将导致查询中的所有Where子句都基于s的最终值。

    正如here 解释的那样,发生这种情况是因为在上面的foreach 循环中声明的s 变量在编译器中是这样翻译的:

    string s;
    while (enumerator.MoveNext())
    {
       s = enumerator.Current;
       ...
    }
    

    而不是这样:

    while (enumerator.MoveNext())
    {
       string s;
       s = enumerator.Current;
       ...
    }
    

    正如here 指出的那样,在循环外声明变量并没有性能优势,在正常情况下,我能想到这样做的唯一原因是,如果您打算在循环:

    string s;
    while (enumerator.MoveNext())
    {
       s = enumerator.Current;
       ...
    }
    var finalString = s;
    

    但是,foreach 循环中定义的变量不能在循环外使用:

    foreach(string s in strings)
    {
    }
    var finalString = s; // won't work: you're outside the scope.
    

    因此,编译器声明变量的方式使其极易出现通常难以发现和调试的错误,同时不会产生明显的好处。

    【讨论】:

    • 问题解决了吗?不确定上面的答案试图告诉我们什么。这只是对 Enigmativity 的回应吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-25
    • 1970-01-01
    相关资源
    最近更新 更多