#c# #xml #linq-to-xml
Вопрос:
У меня есть два правила, которые я хочу реализовать в XML-приложении.
1 Если вес больше 10, то по названию Отдела должно быть написано: Большой
Комментарии:
1. Почему бы вам не проверить свойства, соответствуют ли они условию, и если да, то добавить маркер строки отдела в строку результата? Это не сложная проблема.
2. Вы даже можете встроить условную проверку.
3. Да, но для этого будет чище использовать некоторые шаблоны. Но я застрял здесь.
Ответ №1:
Лучше всего позволить самому Department
свойству вычислить его значение (вычисляемое свойство). Это чище и удобочитаемее, так как вычисления выполняются там, где вы этого ожидаете. В противном случае в сценарии, где вычисления зависят более чем от одного свойства, вы обнаружите, что пишете дублированный вычислительный код в каждом участвующем свойстве.
Поэтому выполняйте вычисление при запросе значения, то есть при вызове вычисляемого свойства Get()
, а не при изменении участвующих свойств. Если вычисления более сложные, то следование этим правилам также повысит производительность.
Также избегайте реализации такого фильтра непосредственно в Set()
/ Get()
свойства. Переместите его в метод.
Я также предлагаю использовать оператор переключения или выражение переключения, поскольку это более читабельно, чем длинная цепочка блоков if-else, и, следовательно, проще в обслуживании. При использовании C# 9 выражение переключения может быть мощным инструментом фильтрации с хорошо читаемым синтаксисом.
Кроме того, поскольку строка, которую вы пытаетесь создать для печати, является фиксированным string
представлением фактического Parcel
экземпляра, было бы более уместно переопределить Parcel.ToString
.
Ваш класс посылок должен выглядеть примерно так:
Посылка.cs
public class Parcel
{
public override string ToString()
=> $"Name: {this.Name} - Postal code {this.PostalCode} - Weight {this.Weight} - Value {this.Value} - Department {this.Department}";
public string Name { get; set; }
public string PostalCode { get; set; }
public decimal Weight { get; set; }
public decimal Value { get; set; }
public string Department => CreateDepartmentValue();
private string CreateDepartmentValue()
{
var result = string.Empty;
switch (this.Weight)
{
case decimal weightInKiloGrams when weightInKiloGrams <= 1: result = "Mail"; break;
case decimal weightInKiloGrams when weightInKiloGrams <= 10: result = "Regular"; break;
case decimal weightInKiloGrams when weightInKiloGrams > 10: result = "Heavy"; break;
};
switch (this.Value)
{
case decimal value when value > 1000: result = ", Insurance"; break;
};
return resu<
}
}
Пример Использования
public class Program
{
static void Main(string[] args)
{
XDocument xdoc = XDocument.Load($"Container.xml");
var items = ...;
foreach (var item in items)
{
// Call ToString() implicitly
Console.WriteLine(item);
Console.WriteLine("*********************************************************************");
}
Console.ReadLine();
}
}
Ответ №2:
Вы можете создать посылку класса и определить отдел на основе веса и значения из вызова функции
public class Parcel
{
public string Name { get; set; }
public string PostalCode { get; set; }
public decimal Weight { get; set; }
public decimal Value { get; set; }
public string Department => GetDepartment();
private string GetDepartment()
{
string _department = "";
if (this.Weight <= 1)
{
_department = "Mail";
}
else if (this.Weight > 1 amp;amp; this.Weight <= 10)
{
_department = "Regular";
}
else if (this.Weight > 10)
{
_department = "Heavy";
}
else
{
_department = "Unknown";
}
if (this.Value > 1000)
{
_department = ",Insurance";
}
return _department;
}
}
Ваш XDcoument
будет выглядеть так, как показано ниже
XDocument xdoc = XDocument.Load($"XMLFile1.xml");
var items = xdoc.Descendants("Parcel")
.Select(xelem => new Parcel
{
Name = xelem.Element("Sender").Element("Name").Value,
PostalCode = xelem.Element("Sender").Element("Address").Element("PostalCode").Value,
Weight = Convert.ToDecimal(xelem.Element("Weight").Value),
Value = Convert.ToDecimal(xelem.Element("Value").Value)
});
foreach (var item in items)
{
Console.WriteLine($"{ item.Name} - { item.PostalCode} - { item.Weight} - { item.Value} - { item.Department}");
}
Выход
Klaas - 2402AE - 0.02 - 0.0 - Mail
ykken groot B.V. - 2497GA - 2.0 - 0.0 - Regular
seti - 2497GA - 100.0 - 2000.0 - Heavy,Insurance
Aad - 2353HS - 11 - 500 - Heavy
Комментарии:
1. Привет, спасибо. Но если я хочу добавить еще одно условие, например: Отдел = Преобразовать. ToDecimal(xelem. Элемент(«Вес»). Значение) «Почта» : Конвертировать. ToDecimal(xelem. Элемент(«Вес»). Значение) > 1000 ? «Большой» : Преобразование. ToDecimal(xelem. Элемент(«Вес»). Значение) > 10 ? «Большой» : «Маленький» }); тогда это не работает
2. Тогда я не вижу почты с именем
3. @mightycodeNewton, я обновил пост более эффективным способом
4. Привет, Кришна, спасибо тебе. Я обновил сообщение. Не могли бы вы взглянуть на него в последний раз? Я также изменил кое-какой код. Спасибо
5. Да, в первой посылке вывода указано 2. Но значение в xml равно 0,02
Ответ №3:
Почему бы не расширить класс посылок, чтобы иметь свойство «DepartmentSize», которое обрабатывает размер:
class Parcel
{
public string DepartmentSize
{
var parts = new List<string>();
if(_Weight> 10)
parts.Append("Big");
if(_Value > 1000)
parts.Append("Large");
return string.Join(",", parts);
}
}
Затем вы можете вывести размер следующим образом:
Console.WriteLine($"... Department: {item.DepartmentSize}");
Комментарии:
1. Спасибо. Но как это связано? Я имею в виду, что посылка класса в данный момент не используется
2. Вы правы, ваш класс посылок не используется. Я так и думал. Тем не менее, в вашей программе вместо создания анонимного типа, почему бы не создать коллекцию посылок (с помощью конструктора), тогда мое решение будет работать.
3. Вы имеете в виду торговца парцеллами?