Linq To Xml Null Проверка атрибутов

<books>
   <book name="Christmas Cheer" price="10" />
   <book name="Holiday Season" price="12" />
   <book name="Eggnog Fun" price="5" special="Half Off" />
</books>

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

var books = from book in booksXml.Descendants("book")
                        let Name = book.Attribute("name") ?? new XAttribute("name", string.Empty)
                        let Price = book.Attribute("price") ?? new XAttribute("price", 0)
                        let Special = book.Attribute("special") ?? new XAttribute("special", string.Empty)
                        select new
                                   {
                                       Name = Name.Value,
                                       Price = Convert.ToInt32(Price.Value),
                                       Special = Special.Value
                                   };

Мне интересно, есть ли лучшие способы решить эту проблему.

Спасибо,

  • Джаред

Ответ 1

Вы можете применить атрибут к string. Если он отсутствует, вы получите null, а последующий код должен проверить на null, иначе он вернет значение напрямую.

Попробуйте это вместо:

var books = from book in booksXml.Descendants("book")
            select new
            {
                Name = (string)book.Attribute("name"),
                Price = (string)book.Attribute("price"),
                Special = (string)book.Attribute("special")
            };

Ответ 2

Как использовать метод расширения для инкапсуляции отсутствующих случаев атрибутов:

public static class XmlExtensions
{
    public static T AttributeValueOrDefault<T>(this XElement element, string attributeName, T defaultValue)
    {
        var attribute = element.Attribute(attributeName);
        if (attribute != null && attribute.Value != null)
        {
            return (T)Convert.ChangeType(attribute.Value, typeof(T));
        }

        return defaultValue;
    }
}

Обратите внимание, что это будет работать, только если T - тип, который строка знает, чтобы преобразовать через IConvertible. Если вы хотите поддерживать более общие случаи конверсии, вам может потребоваться также поиск TypeConverter. Это вызовет исключение, если тип не будет преобразован. Если вы хотите, чтобы эти случаи также возвращали значение по умолчанию, вам необходимо выполнить дополнительную обработку ошибок.

Ответ 3

В С# 6.0 вы можете использовать монадический оператор Null-условный ?. После применения его в вашем примере это будет выглядеть так:

var books = from book in booksXml.Descendants("book")
            select new
            {
                Name = book.Attribute("name")?.Value ?? String.Empty,
                Price = Convert.ToInt32(book.Attribute("price")?.Value ?? "0"),
                Special = book.Attribute("special")?.Value ?? String.Empty
            };

Вы можете прочитать здесь в разделе "Операторы с нулевым условием".