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);