代码之家  ›  专栏  ›  技术社区  ›  DaveDev

linq to xml-如何从匿名对象获取字典?

  •  2
  • DaveDev  · 技术社区  · 14 年前

    目前,我正在从以下XML代码段获取HeaderColumn列表:

    <PerformancePanel>
      <HeaderColumns>
        <column performanceId="12" text="Over last month %" />
        <column performanceId="13" text="Over last 3 months %" />
        <column performanceId="16" text="1 Year %" />
        <column performanceId="18" text="3 Years % p.a." />
        <column performanceId="20" text="5 Years % p.a." />
        <column performanceId="22" text="10 Years % p.a." />
      </HeaderColumns>
    </PerformancePanel>
    

    从中我创建了一个如下的对象:(令人信服地类似于前面的问题!)

    var performancePanels = new
    {
        Panels = (from panel in doc.Elements("PerformancePanel")
                select new
                {
                    HeaderColumns = (from column in panel.Elements("HeaderColumns").Elements("column")
                                     select new
                                     {
                                         PerformanceId = (int)column.Attribute("performanceId"),
                                         Text = (string)column.Attribute("text")
                                     }).ToList(),
                  }).ToList()
    };
    

    如果headercolumns是一个字典(),那么稍后我将从匿名对象中提取值,如下所示:

    Dictionary<int, string> myHeaders = new Dictionary<int, string>();
    foreach (var column in performancePanels.Panels[0].HeaderColumns)
    {
        myHeaders.Add(column.PerformanceId, column.Text);
    }
    

    我想我可以用linq-to-xml实现这一点

    HeaderColumns = (from column in panel.Elements("HeaderColumns").Elements("column")
                     select new Dictionary<int, string>()
                     {
                         (int)column.Attribute("performanceId"),
                         (string)column.Attribute("text")
                     }).ToDictionary<int,string>(),
    

    但这不起作用,因为

    1. toDictionary()需要一个func参数,我不知道 这是什么/如何实现它, 和
    2. 无论如何,代码可能是错误的!

    有人能建议我怎样才能达到我需要的结果吗?谢谢。

    编辑: 我试图在下面实现斯宾德的解决方案,但我很难理解我需要在代码中更改什么。有人能解释清楚吗?谢谢

    3 回复  |  直到 14 年前
        1
  •  2
  •   spender    14 年前

    这是未经测试的,但应该做到这一点:

    panel
        .Elements("HeaderColumns")
        .Elements("column")
        .ToDictionary(
            column=>(int)column.Attribute("performanceId"),
            column=>(string)column.Attribute("text")
        )
    

    在这种情况下,我使用以下 overload of ToDictionary :

    public static Dictionary<TKey, TElement> ToDictionary<TSource, TKey, TElement>(
        this IEnumerable<TSource> source,
        Func<TSource, TKey> keySelector,
        Func<TSource, TElement> elementSelector
    )
    

    所以,在这里 source 将是:

    panel
        .Elements("HeaderColumns")
        .Elements("column")
    

    keySelector elementSelector 是接受类型为tssource(from)的元素的函数(委托) 来源 ,并返回从元素派生的值:

    键选择器 :

            column=>(int)column.Attribute("performanceId")
    

    元件选择器 :

            column=>(string)column.Attribute("text")
    

    这些是以lambda格式声明的。然后从这些委托的返回类型推断字典的类型。这将是 Dictionary<int,string> 在这种情况下。

    一般委托 Func<TSource, TKey> 将定义一个方法的类型,该方法接受类型为tssource的参数并返回类型为tkey的值。使用LINQ扩展方法来处理这意味着什么的问题非常重要。

        2
  •  1
  •   Marc Gravell    14 年前

    很难给出一个完整的答案,因为XML和C不匹配;但是从每个“headercolumns”中可以使用:

    var columns = from column in headerColumns.Elements("column")
                  select new {
                      PerformanceId = (int)column.Attribute("performanceId"),
                      Text = (string)column.Attribute("text")
                  };
    Dictionary<int, string> myHeaders = columns.ToDictionary(
        column => column.PerformanceId, column => column.Text);
    

    如果你有多个 <HeaderColumns> 然后 SelectMany 也许吧。。。

    var columns = from panel in doc.Elements("PerformancePanel")
                  from headers in panel.Elements("HeaderColumns")
                  from column in headers.Elements("column")
                  select new {
                      PerformanceId = (int)column.Attribute("performanceId"),
                      Text = (string)column.Attribute("text")
                  };
    Dictionary<int, string> myHeaders = columns.ToDictionary(
        column => column.PerformanceId, column => column.Text);
    
        3
  •  0
  •   Community datashaman    7 年前

    我发现这是这个问题的一个合适答案:

    How to Create Dictionary<int, string> via LINQ to XML?