Не удается неявно преобразовать тип 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)
И через динамический объект вы можете найти свойства во время выполнения.
Надеюсь, что это поможет вам.