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

时间:2014-04-27 11:28:36

标签: c# linq linq-to-xml

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

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

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

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

错误告诉我问题出现在InvoiceLines中的“select new XElement ...”行中

3 个答案:

答案 0 :(得分:2)

如果没有找到匹配的元素或属性,可以导致.Value,而不是使用NullReferenceException,我建议使用(string)强制转换,只需生成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") ?? ""));  

答案 1 :(得分:1)

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

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

该段代码假定:

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

    这些假设贯穿整个那条线。因此,如果遇到不符合这些假设的数据,.Element().Attribute()可能会返回null,在这种情况下,下一个.(例如{{1} }})会尝试取消引用.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,您可以取消第一次检查。但是你的其他部分仍然会进行一些嵌套检查。

    要将其拆分,您必须循环使用值而不是使用单个LINQ语句。像这样的结构:

    null

    这不是 100%相同,因为它急切加载整个集合。所以你也可以把循环本身分成另一个方法,它返回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 } 并使用IEnumerable<XElement>来不必急于加载整个东西。这取决于你。

    想想看,你的初始数据选择器也做出了假设:

    yield return

    您可能还希望在此处添加Document.Root.Element(P + "InvoiceLines").Elements(P + "InvoiceLine") 检查,以防您收到与这些谓词不匹配的数据。

答案 2 :(得分:0)

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

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

如果没有元素P + "ID",则在访问NullReferenceException引用的Value属性时,上面的行会抛出null。您可能需要执行类似

的操作
e.Element(P + "ID") ?? 0

其中0是您希望它拥有的默认值。或者你可以通过一个老式的for循环和一些if循环来实现这一点。