Не удается неявно преобразовать тип System.Collections.Generic.Dictionary<System.Tuple <int, int, string>, AnonymousType # 1>

У меня есть следующий словарь в методе:

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 ответа

Решение

Когда вы звоните 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> или что-то еще здесь, если хотите, но результирующий обобщенный тип очень быстро станет громоздким.)

Краткий ответ: вы не можете возвращать анонимные типы из функции.

Длинный ответ: тип значения вашего словаря является анонимным {BaseHours, OvertimeHours} который не может быть возвращен из функции или передан в качестве аргумента (кроме как в виде объекта, но это никому не приносит пользы, если вы не проходите через трудности с отражением в нем). Либо определите класс / структуру с BaseHours а также OvertimeHours в нем или используйте кортеж. Первое, вероятно, немного лучше, потому что вы можете сохранить имена BaseHours а также OvertimeHours; с кортежем вы просто получаете Value1 а также Value2,

Если вы используете C# 4.0, вы можете вернуть анонимный через динамический тип. Таким образом, подпись вашего метода будет выглядеть так

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

И через динамический объект вы можете найти свойства во время выполнения.

Надеюсь, что это поможет вам.

Другие вопросы по тегам