用于从XML创建对象和更新其属性的更好代码

本文关键字:属性 更好 代码 更新 XML 创建对象 用于 | 更新日期: 2023-09-27 18:04:56

我有多个Invoice元素的XML输入。我从这些元素创建发票对象。根据invoice元素的位置,我们需要分配序列号,并从另一个元素StatusMsg中找到相应的消息。

我有以下c#代码在。net 4.0。它工作得很好,可读性也很好。在不牺牲readability的情况下,是否有更好的performance代码?

// Create a collection of invoice elements
var invoiceEntities = xDoc.Descendants("Invoice")
              .Select(x => new Invoice
               {
                  Vendor = x.Element("Vendor") == null ? String.Empty : x.Element("Vendor").Value.Trim(),
                  Amount = x.Element("Amount") == null ? String.Empty : x.Element("Amount").Value.Trim()
               });
List<Invoice> invoices = invoiceEntities.ToList();
//Iterate all entities for finding corresponding message element and update the entity's Message
int count = 0;
foreach (Invoice entity in invoices)
{
           count++;
           //Dynamic XPath statement
           string messagePath = @"Status/StatusMsg/StatusDetail/Sequence[text()=" + count.ToString() + "]/../Message";
           var statusDetails = xDoc.XPathSelectElements(messagePath).FirstOrDefault();
           if (statusDetails != null)
           {
               entity.Message = statusDetails.Value;
               entity.Sequence = count;
           }
  }

实体

public class Invoice
{
    public string Vendor { get; set; }
    public string Amount { get; set; }
    public string Message { get; set; }
    public int Sequence { get; set; }
}
XML>
  XDocument xDoc = XDocument.Parse(@"  
          <Status>
                <StatusMsg>
                    <StatusType>INVOICE</StatusType>
                    <StatusCode>READYPAY</StatusCode>
                    <StatusTimestamp>2013-03-19T21:20:54Z</StatusTimestamp>
                    <StatusDetail>
                        <Sequence test=""K"">  2  </Sequence>
                        <Message>STL MESSAGE </Message>
                    </StatusDetail>
                    <StatusDetail>
                        <Sequence test=""1"">  1  </Sequence>
                        <Message>AKP MESSAGE</Message>
                    </StatusDetail>
                    <StatusDetail>
                        <Sequence> 1 </Sequence>
                        <Message>CC</Message>
                    </StatusDetail>
                </StatusMsg>
                <Invoices> 
                    <Invoice>
                        <Vendor>
                         AKP LLC
                        </Vendor>
                        <Amount>
                         100
                        </Amount>
                    </Invoice>
                    <Invoice>
                        <Vendor>
                         STL Inc
                        </Vendor>
                        <Amount>
                         20950
                        </Amount>
                    </Invoice>
                </Invoices>
            </Status>
           ");

引用:

  1. 生成c#目标代码并从xml文档中为其属性赋值
  2. 使用注释将LINQ转换为XSLT风格的XML树- Eric White
  3. XSLT或Linq to XML的优点

用于从XML创建对象和更新其属性的更好代码

关于我唯一可以真正推荐的是将StatusDetail节点存储在列表中,只需抓住它们的全部,然后您可以通过第二个linq语句引用列表来过滤序列。不过,这最终可能比简单地构建和重用XPath字符串要慢。

var Details = xDoc.Descendants("StatusDetail").ToList();
...
var statusDetail = Details.Where(a => a.Sequence == count).FirstOrDefault();

作为一个挑剔的开发点,通常建议在做这样奇怪的连接字符串时使用String.Format…关于反向代码更高效的事情…

string messagePath = String.Format("Status/StatusMsg/StatusDetail/Sequence[text()={0}]/../Message", count);

另一个选项,您已经构建了一个匿名类型,没有理由不将count构建到Invoice选项中。这至少使您不必在循环中分别声明和维护count。

int count = 1;
var invoiceEntities = xDoc.Descendants("Invoice")
          .Select(x => new Invoice
           {
              Vendor = x.Element("Vendor") == null ? String.Empty : x.Element("Vendor").Value.Trim(),
              Amount = x.Element("Vendor") == null ? String.Empty : x.Element("Amount").Value.Trim(),
              Index = count++
           });//yes that works, I tested it because even I wasn't sure, but Index is correct and different for each element