无法隐式转换类型System.Collections.Generic.Dictionary <system.tuple <int,int,string>,AnonymousType#1&gt; </system.tuple <int,int,string>

时间:2012-08-14 18:20:45

标签: c# linq-to-xml idictionary

我在方法中有以下字典:

var nmDict = xelem.Descendants(plantNS + "Month").ToDictionary(
    k => new Tuple<int, int, string>(int.Parse(k.Ancestors(plantNS + "Year").First().Attribute("Year").Value), Int32.Parse(k.Attribute("Month1").Value), k.Ancestors(plantNS + "Report").First().Attribute("Location").Value.ToString()),
    v => { 
             var detail = v.Descendants(plantNS + "Details").First();                
             return
                 new
                    {
                      BaseHours = detail.Attribute("BaseHours").Value,
                      OvertimeHours = detail.Attribute("OvertimeHours").Value
                    };
         });

我需要返回nmDict。问题是我无法弄清楚如何标记我的方法签名。我尝试过以下方法:

protected IDictionary<XElement, XElement> OvertimereportData(HarvestTargetTimeRangeUTC ranges)

上面给出了这个错误:

Cannot implicitly convert type System.Collections.Generic.Dictionary<System.Tuple<int,int,string>,AnonymousType#1>' to 'System.Collections.Generic.IDictionary<System.Xml.Linq.XElement,System.Xml.Linq.XElement>'. An explicit conversion exists (are you missing a cast?) 


protected IDictionary<Tuple, XElement> OvertimereportData(HarvestTargetTimeRangeUTC ranges)

给了我这个错误:

'System.Tuple': static types cannot be used as type arguments   

我不知道该怎么做。

3 个答案:

答案 0 :(得分:3)

简短回答:您无法从函数返回匿名类型。

答案很长:你的字典的值类型是匿名{BaseHours, OvertimeHours},它不能从函数返回或作为参数传递(除了作为一个对象,但除非你经历反思的麻烦,否则没有任何好处进去)。要么定义一个包含BaseHoursOvertimeHours的类/结构,要么使用元组。前者可能略好一些,因为您可以保留名称BaseHoursOvertimeHours;使用元组,您只需获得Value1Value2

答案 1 :(得分:2)

如果您使用的是C#4.0,则可以通过 dynamic 类型返回匿名。所以你的方法签名看起来像这样

protected IDictionary<Tuple<int,int,string>, dynamic> OvertimereportData(HarvestTargetTimeRangeUTC ranges)

通过动态对象,您可以在运行时找到属性。

希望这会对你有所帮助。

答案 2 :(得分:1)

当您调用ToDictionary方法时,生成的字典的类型与源序列中的元素类型几乎没有关系。它完全由您为调用提供的键和值表达式返回的数据类型定义。例如,如果你打电话:

xelem.Descendants(plantNS + "Month").ToDictionary(
  k => int.Parse(k.Attribute("Year").Value),
  v => k.Attribute("Year).Value
);

你会得到IDictionary<int, string>,因为这是你的两个表达式返回的内容。要从方法返回它,您只需要根据表达式构造正确的类型。

你的第一个很容易:

k => new Tuple<int, int, string>(...)

然而,第二个问题将是一个问题。字典中的值是匿名类型:返回new { }而不指定该值的具体类型名称。通常,这将使您无法将该字典用作返回值或参数。 (可以完成,使用一些非常奇怪的通用技术,但我不推荐它。)

然后,你需要做的第一件事是制作一个具体的类型来保存你的价值观,例如。

public class HoursContainer 
{
  public string BaseHours { get; set; }
  public string OvertimeHouse { get; set; }
}

并适当更改您的Linq查询:

var detail = v.Descendants(plantNS + "Details").First();                
return new HoursContainer
{
    BaseHours = detail.Attribute("BaseHours").Value,
    OvertimeHours = detail.Attribute("OvertimeHours").Value
};

完成此操作后,您的词典将根据您在创建时指定的内容类型具有具体类型:

IDictionary<Tuple<int, int, string>, HoursContainer>

(注意:如果你愿意的话,你也可以使用另一个Tuple<int, int>或其他任何东西,但是生成的泛型类型会很快变得笨拙。)