对象引用未设置为使用 LINQ C# 的对象实例

本文关键字:对象 实例 LINQ 设置 对象引用 | 更新日期: 2023-09-27 18:00:27

我解决了命名空间问题,但我仍然有错误消息。我认为问题在于将信息放入列表中

IEnumerable<XElement> InvoiceLines = from e in Document.Root
                                        .Element(P + "InvoiceLines")
                                        .Elements(P + "InvoiceLine")
                        select new XElement("InvoiceLine",
                    new XAttribute("LineNumber", e.Element(P + "ID").Value),
                    new XAttribute("ProductName", e.Element(P + "Item").Attribute(P + "Description").Value),
                    new XAttribute("UnitPriceTaxInclusive", e.Element(P + "UnitPriceTaxInclusive").Value),
                    new XAttribute("Quantity", e.Element(P + "InvoicedQuantity").Value),
                    new XAttribute("UnitCode", e.Element(P + "InvoicedQuantity").Attribute(P + "@unitCode").Value));  

然后我尝试使用此发票行保存文档,如下所示:

XDocument FinalDocument = new XDocument( 
            new XElement("Invoice",
            new XAttribute("BuyerName", BuyerName),
            new XAttribute("SellerName", SellerName),
            new XAttribute("IssueDate", IssueDate),
            new XAttribute("ID", InvoiceID),
            new XElement("InvoiceLines", InvoiceLines)
            ));
        FinalDocument.Save(name);
        FinalDocument.Save(Console.Out);

错误告诉我问题出在"选择新的XElement..."在发票行中

对象引用未设置为使用 LINQ C# 的对象实例

与其使用 .Value ,如果没有找到

匹配的元素或属性,可能会导致NullReferenceException,我建议使用 (string) 强制转换,如果没有找到有效值,这将简单地产生null,并且 null 合并运算符??

IEnumerable<XElement> InvoiceLines = 
        from e in Document.Root
                          .Element(P + "InvoiceLines")
                          .Elements(P + "InvoiceLine")
        select new XElement("InvoiceLine",
                 new XAttribute("LineNumber", (string)e.Element(P + "ID") ?? ""),
                 new XAttribute("ProductName", (e.Element(P + "Item") != null) ? (string)e.Element(P + "Item").Attribute(P + "Description") ?? "" : ""),
                 new XAttribute("UnitPriceTaxInclusive", (string)e.Element(P + "UnitPriceTaxInclusive") ?? ""),
                 new XAttribute("Quantity", (string)e.Element(P + "InvoicedQuantity") ?? ""),
                 new XAttribute("UnitCode", (string)e.Element(P + "InvoicedQuantity").Attribute(P + "@unitCode") ?? ""));  

这行代码对基础数据有很多假设。 例如,这个:

e.Element(P + "Item").Attribute(P + "Description").Value

该代码段假定:

  1. e保证包含与元素匹配的P + "Item"
  2. 保证该元素包含与P + "Description"匹配的属性

这些假设贯穿了整条线。 因此,如果遇到不符合这些假设的数据,.Element().Attribute()可能会返回null,在这种情况下,下一个.(例如在.Value中(将尝试取消引用null值,从而导致该错误。

要添加一些空值检查,您可以将其分成多行代码或将其全部内联。 这两种方法的可读性和可维护性都取决于您。 例如,对于此段:

new XAttribute("LineNumber", e.Element(P + "ID").Value)

您可以添加一些错误检查,如下所示:

new XAttribute("LineNumber", 
    (e == null ? string.Empty : 
        (e.Element(P + "ID") == null ? string.Empty :
            e.Element(P + "ID").Value)))

我可以看到这可能非常不可读的地方。 您也许可以消除第一次检查,假设e本身永远不会null。 但是您的其他细分仍将有一些嵌套检查。

若要将其分开,必须遍历值,而不是使用单个 LINQ 语句。 像这样的结构:

var InvoiceLines = new List<XElement>();
foreach (var e in Document.Root.Element(P + "InvoiceLines").Elements(P + "InvoiceLine"))
{
    // build an XElement object from e and add it to the list
}

这不是 100% 相同的,因为它急切地加载整个集合。 因此,您也可以将循环本身分离到另一个返回IEnumerable<XElement>的方法中,并使用yield return不必急于加载整个内容。 这取决于你。

想想看,您最初的数据选择器也会做出假设:

Document.Root.Element(P + "InvoiceLines").Elements(P + "InvoiceLine")

您可能还希望在此处添加null检查,以防万一您收到与这些谓词不匹配的数据。

文档中可能不存在您的某些元素或属性。例如:

e.Element(P + "ID").Value

如果没有元素P + "ID"则上面的行将在访问null引用的 Value 属性时引发NullReferenceException。您可能需要执行以下操作

e.Element(P + "ID") ?? 0

其中 0 是您希望它具有的默认值。或者你可以用一个老式的for循环和一些if循环来做到这一点。