Явное приведение Linq-to-XML в универсальном методе - PullRequest
2 голосов
/ 07 февраля 2011

Я искал похожий вопрос, но единственный, который был близок, не помог мне в конце.

У меня есть XML-файл, который выглядит следующим образом:

<Fields>
    <Field name="abc" value="2011-01-01" />
    <Field name="xyz" value="" />
    <Field name="tuv" value="123.456" />
</Fields>

Я пытаюсь использовать Linq-to-XML, чтобы получить значения из этих полей. Значения могут быть типа Decimal, DateTime, String и Int32. Мне удалось получить поля одно за другим, используя относительно простой запрос. Например, я получаю 'значение' из поля с именем 'abc', используя следующее:

private DateTime GetValueFromAttribute(IEnumerable<XElement> fields, String attName)
{
    return (from field in fields
           where field.Attribute("name").Value == "abc"
           select (DateTime)field.Attribute("value")).FirstOrDefault()
}

это помещается в отдельную функцию, которая просто возвращает это значение, и все работает отлично (так как я знаю, что есть только один элемент с атрибутом имени, установленным в 'abc'). однако, поскольку я должен сделать это для десятичных, целых чисел и дат, мне было интересно, смогу ли я создать универсальную функцию, которая работает во всех случаях. это где я застрял. вот что у меня так далеко:

private T GetValueFromAttribute<T>(IEnumerable<XElement> fields, String attName)
{
    return (from field in fields
            where field.Attribute("name").Value == attName
            select (T)field.Attribute("value").Value).FirstOrDefault();
}

это не компилируется, потому что не знает, как конвертировать из String в T. Я пробовал упаковывать и распаковывать (то есть select (T) (Object) field.Attribute("value").Value, но это вызывает исключение Specified cast is not valid во время выполнения, когда он пытается преобразовать String в DateTime, например.

Возможно ли это в универсальной функции? я могу наложить ограничение на универсальную функцию, чтобы она работала? или мне нужно иметь отдельные функции, чтобы использовать преимущества явных операторов приведения Linq-to-XML?

Ответы [ 3 ]

4 голосов
/ 07 февраля 2011

Вы можете попробовать сделать это следующим образом:

public static T GetValueFromAttribute<T>(IEnumerable<XElement> fields, String attName)
{
  return (from field in fields
          where field.Attribute("name").Value == attName
          select (T)Convert.ChangeType(field.Attribute("value").Value, typeof(T))).FirstOrDefault();
}

Это будет работать для DateTime, int и т. Д. (Все типы, реализующие IConvertible).

2 голосов
/ 07 февраля 2011

Вы не можете использовать перегрузку операторов таким образом, нет. Самое близкое, что вы приедете, будет иметь что-то вроде:

private T GetValueFromAttribute<T>(IEnumerable<XElement> fields, 
                                   string attName,
                                   Func<XAttribute, T> selector)
{
    return fields.Where(field => field.Attribute("name").Value == attName)
                 .Select(field => selector(field.Attribute("value")))
                 .FirstOrDefault();
}

, затем назовите его с помощью:

GetValueFromAttribute(fields, "foo", attr => (DateTime) attr);
0 голосов
/ 07 февраля 2011

Нет, приведение к универсальной переменной T всегда выполняет приведение; Вместо этого не делается попытка вызвать явный или неявный оператор преобразования .


Я бы предложил отказаться от идеи вызова метода для каждого элемента, значение которого вы хотите получить, и вместо этого выполнить итерацию перечислимых элементов:

foreach (var field in fields.Elements("field"))
{
    var name = field.Attribute("name");
    var value = field.Attribute("value");

    switch ((string)name)
    {
    case "abc":
        var result = (DateTime)value;
        :
        :
    }
}
...