Decimal.TryParse в запросе LINQ - как использовать параметр out и избежать повторного преобразования

Я использую запрос LINQ to XML, чтобы пройти через файл XML и собрать те узлы, где баланс положительный. XML может иметь пустой узел баланса или содержать содержимое, которое не может быть преобразовано в десятичное, поэтому у меня есть проверки, чтобы пропустить такие значения. Одна из использованных проверок decimal.TryParse() чтобы увидеть, можно ли преобразовать содержимое узла баланса в десятичное. Если это может быть преобразовано, у меня есть последующее условие Where, которое выполняет преобразование.

XML структура:

<Invoice>
...
  <balance>Could be any string here or empty</balance>
...
</Invoice>

Код:

decimal convertedDecimalButUnused;
var resultsWithPositiveBalance = xml.Descendants("Invoice")
.Where(x => !x.Element("balance").IsEmpty);
.Where(x => Decimal.TryParse(x.Element("balance").Value, out convertedDecimalButUnused))
.Where(x => Convert.ToDecimal(x.Element("balance").Value) > 0);

Мой вопрос, могу ли я использовать out параметр decimal.TryParse() вместо выполнения десятичного преобразования во второй раз?

3 ответа

Решение

Просто сделайте сравнение в соответствии с TryParse. Вы можете воспользоваться функцией C#7, позволяющей объявлять значение в строке.

Например:

var resultsWithPositiveBalance = xml.Descendants("Invoice")
.Where(x => !x.Element("balance").IsEmpty);
.Where(x => Decimal.TryParse(x.Element("balance").Value, out var val) && val > 0)

Так как TryParse будет обрабатывать, если элемент для вас уже пуст, вы также можете отказаться от проверки. В конце вы можете получить желаемый результат с помощью этого:

var resultsWithPositiveBalance = xml.Descendants("Invoice")
.Where(x => decimal.TryParse(x.Element("balance").Value, out var val) && val > 0);

Да, ты можешь это сделать:

decimal convertedDecimalButUnused;
var resultsWithPositiveBalance = xml.Descendants("Invoice")
.Where(x => !x.Element("balance").IsEmpty);
.Where(x => Decimal.TryParse(x.Element("balance").Value, out convertedDecimalButUnused) && convertedDecimalButUnused > 0);

Вы можете связать несколько утверждений вместе внутри функции Where, используя && что приравнивается к AND.

Попробуйте написать метод расширения утилиты, который преобразует XElement в десятичный. В этом случае вы можете рассматривать недесятичные значения как ноль, так как вас интересуют только положительные значения. Если вы хотите провести различие между действительным значением 0 и недесятичным значением, то метод может вернуть нулевое десятичное значение.

public static class UtilityExtensions {
    // return decimal? to differentiate between real zero and non-decimal values
    public static decimal ToDecimal(this XElement element){
        if(element == null || element.IsEmpty) return 0; // return null for decimal?
        decimal value;
        // if you can use C# 7, code can be more succinct with inline declaration
        return Decimal.TryParse(element.Value, out value) ? value : 0; // return null instead of 0 for decimal?
    }
}

Теперь ваш LINQ намного проще. Это также будет обрабатывать случай, когда сам элемент "balance" отсутствует.

var resultsWithPositiveBalance = xml.Descendants("Invoice")
         .Where(x => !x.Element("balance").ToDecimal() > 0);

В случае, если вы в конечном итоге использовать decimal? версия:

var resultsWithPositiveBalance = xml.Descendants("Invoice")
         .Where(x => (!x.Element("balance").ToDecimal() ?? 0 ) > 0);
Другие вопросы по тегам