如何处理缺少元素时失败的 LINQ 表达式

发布于 2024-12-01 15:05:22 字数 10294 浏览 1 评论 0原文

我是 LINQ to XML 的新手,我已经得到了这段可以工作的代码(大多数时候):

private long processFile(StreamWriter oWriter, string inFileName)
    {
        XDocument xmlDoc = XDocument.Load(inFileName);
        List<DocMetaData> docList =
            (from d in xmlDoc.Descendants("DOCUMENT")
             select new DocMetaData
             {
                 Folder = d.Element("FOLDER").Attribute("name").Value
                 ,
                 File = d.Element("FILE").Attribute("filename").Value
                 ,
                 Comment = d.Elements("INDEX")
                    .Where(i => i.Attribute("name").Value == "Comment(idmComment)")
                    .First()
                    .Attribute("value").Value
                 ,
                 Title = d.Elements("INDEX")
                    .Where(i => i.Attribute("name").Value == "Title(idmName)")
                    .First()
                    .Attribute("value").Value
                 ,
                 DocClass = d.Elements("INDEX")
                    .Where(i => i.Attribute("name").Value == "Document Class(idmDocType)")
                    .First()
                    .Attribute("value").Value
             }
            ).ToList<DocMetaData>();
        OutputListToFile(oWriter, docList);
        return docList.LongCount();
    }

这在第 117 行(选择表达式)上失败了:

    System.NullReferenceException: Object reference not set to an instance of an object.
   at CBMI.WinFormsUI.GridForm.<processFile>b__3(XElement d) in C:\ProjectsVS2010\CBMI.LatitudePostConverter\CBMI.LatitudePostConverter\CBMI.WinFormsUI\GridForm.cs:line 117
   at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
   at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
   at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
   at CBMI.WinFormsUI.GridForm.processFile(StreamWriter oWriter, String inFileName) in C:\ProjectsVS2010\CBMI.LatitudePostConverter\CBMI.LatitudePostConverter\CBMI.WinFormsUI\GridForm.cs:line 115
   at CBMI.WinFormsUI.GridForm.btnProcess_Click(Object sender, EventArgs e) in C:\ProjectsVS2010\CBMI.LatitudePostConverter\CBMI.LatitudePostConverter\CBMI.WinFormsUI\GridForm.cs:line 85

数据是格式良好的 XML。此给定 XML 文件中有许多 节点,并且大多数(但不是全部) 节点都包含 > 节点。我通过使用 VStudio 2010 强力打开 XML 文件并使用 Find 命令来发现这一点,该命令给出了匹配行的计数。

有没有办法改进 LINQ,使其在数据不完美时不会失败?并且,有没有办法查看 LINQ 表达式的哪一部分实际上失败了(我猜测这是由于缺少 节点,但这可能是错误的并且是一个丑陋的暴力解决问题的方法)。

这是一个确实包含正确的 节点(在最底部)的

    <?xml version="1.0" ?>
<DOCUMENTCOLLECTION>
<DOCUMENT>
<FILE filename="P:\LatitudeConsulting\LatConConverter-1.8.2\ConverterOutput\B0000002\3rd Party CON\D003694452.0001.tif" 
      outputpath="P:\LatitudeConsulting\LatConConverter-1.8.2\ConverterOutput\B0000002\3rd Party CON"/>
<ANNOTATION filename=""/>
<INDEX name="Access Level(idmAccessLevel)" value="Admin"/>
<INDEX name="Added By Group(idmAddedByGroup)" value="General Users"/>
<INDEX name="Added By User(idmDocOwner)" value="Import"/>
<INDEX name="Allow Secondary Version Lines?(idmDocVariants)" value="Yes"/>
<INDEX name="Application(idmVerApplication)" value=""/>
<INDEX name="Archive Category(idmDocDispCategory)" value="Archive"/>
<INDEX name="Archive Date(idmVerDispDate)" value=""/>
<INDEX name="Archive Repository(idmVerDispId)" value=""/>
<INDEX name="ArchivedDocument" value="NO"/>
<INDEX name="Availability Status(idmVerAvailStat)" value="Online"/>
<INDEX name="CAN(idmDocCustom4)" value=""/>
<INDEX name="Checked In By Group(idmVerCheckinGroup)" value="General Users"/>
<INDEX name="Checked In By User(idmVerCheckinUser)" value="Import"/>
<INDEX name="Checked Out?(idmVerCheckoutPending)" value="No"/>
<INDEX name="Checkin Date(idmVerCreateDate)" value="3/9/2001 9:20:38 AM"/>
<INDEX name="Child Count(idmVerCD)" value="0"/>
<INDEX name="Comment(idmComment)" value="1983\06_June_Meeting"/>
<INDEX name="Comment(idmVerComment)" value=""/>
<INDEX name="Content Search Repository(idmVerCsiId)" value=""/>
<INDEX name="Current Content Srch Repository(idmDocCurVerCsiId)" value=""/>
<INDEX name="Current Version Author(idmAddedByUser)" value="Import"/>
<INDEX name="Current Version Checked Out?(idmDocCurVerCheckedOut)" value="No"/>
<INDEX name="Current Version Date(idmDocCurVerDate)" value="3/9/2001 9:20:38 AM"/>
<INDEX name="Current Version ID(idmDocCurVerNum)" value="1"/>
<INDEX name="Current Version Index ID(idmDocCurVerCsiCid)" value=""/>
<INDEX name="Date Added(idmDateAdded)" value="3/9/2001 9:20:37 AM"/>
<INDEX name="Default Index Versions?(idmDocCsiDefault)" value="No"/>
<INDEX name="DiagnosticID(idmDocCustom5)" value="2-16.MDB-00015"/>
<INDEX name="Document Class(idmDocType)" value="3rd Party CON"/>
<INDEX name="Encrypted File Name(idmVerShelfFileId)" value="_276no__.__1"/>
<INDEX name="ExternalDocument" value="NO"/>
<INDEX name="File Name" value="51099.TIF"/>
<INDEX name="File Name(idmVerFileName)" value="51099.TIF"/>
<INDEX name="File Size(idmVerFileSize)" value="1166770"/>
<INDEX name="Has Annotations?(idmAnnotation)" value=""/>
<INDEX name="Index ID(idmVerCsiCid)" value=""/>
<INDEX name="Indexed Version Limit(idmDocCsiLimit)" value="1"/>
<INDEX name="Indexing Status(idmVerCsiStatus)" value="Not Indexed"/>
<INDEX name="Item ID(idmId)" value="003694452"/>
<INDEX name="Item ID(idmVerDocId)" value="003694452"/>
<INDEX name="Keyword(idmDocKeywords)" value=""/>
<INDEX name="Last Access Date(idmDateAccessed)" value="11/28/2003 3:05:30 PM"/>
<INDEX name="Last Access Date(idmDateModified)" value="8/24/2011 5:52:34 PM"/>
<INDEX name="Last Access Group(idmVerLastGroup)" value="Administrators"/>
<INDEX name="Last Access User(idmModifiedByUser)" value="Admin"/>
<INDEX name="Last Accessed Version(idmDocLastVerId)" value="1"/>
<INDEX name="Latest Version?(idmVerBranchCurVer)" value="Yes"/>
<INDEX name="Merge-Destination Version ID(idmVerMergeDst)" value="0"/>
<INDEX name="Merge-Source Version ID(idmVerMergeSrc)" value="0"/>
<INDEX name="MimeType" value="image/tiff"/>
<INDEX name="Min Item Delete Access Level(idmDocDeleteAccess)" value=""/>
<INDEX name="Modification Date(idmVerFileDate)" value="12/19/2000 11:12:30 AM"/>
<INDEX name="Number of Indexed Versions(idmDocCsiCount)" value="0"/>
<INDEX name="Offline Location(idmVerOfflineLocation)" value=""/>
<INDEX name="Online Disk Space(idmDocOnlineSize)" value="1166770"/>
<INDEX name="Online Limit(idmDocOnlineLimit)" value="5"/>
<INDEX name="Online Version Count(idmDocOnlineCount)" value="1"/>
<INDEX name="Origin ID(idmDocOriginID)" value=""/>
<INDEX name="Origin Library(idmDocOriginLibrary)" value=""/>
<INDEX name="Original File Name(idmDocOriginalFile)" value="51099.TIF"/>
<INDEX name="Permanent Index?(idmVerCsiPermanent)" value="No"/>
<INDEX name="Permanent Version?(idmVerPermanent)" value="No"/>
<INDEX name="Property ID(idmDocDynPropertyId)" value=""/>
<INDEX name="Protected?(idmDocProtected)" value="Yes"/>
<INDEX name="Publishing Status(idmPublish)" value=""/>
<INDEX name="Reclaim Pending?(idmVerReclaimPending)" value=""/>
<INDEX name="Reclaim Submitted Date(idmVerReclaimDate)" value=""/>
<INDEX name="Replica?(idmDocIsReplica)" value="No"/>
<INDEX name="ReplicatedDocument" value="NO"/>
<INDEX name="Secondary Version Line Count(idmVerBranchCount)" value="0"/>
<INDEX name="Source Version Checkout Date(idmVerPrevCheckoutDate)" value=""/>
<INDEX name="Storage Category(idmDocFileCategory)" value="Documents"/>
<INDEX name="Storage Repository(idmVerShelfId)" value="2"/>
<INDEX name="Title(idmName)" value="3rd Party CON Comments"/>
<INDEX name="Version ID(idmVerId)" value="1"/>
<FOLDER name="/NACAIE/1983/06_June_Meeting/NAPNSC"/>
</DOCUMENT>

编辑:解决方案如下(包含解决此问题的 LINQ) FOLDER 节点可能丢失;正如其他人指出的那样,使用 First() 可能是危险的做法,但在这种情况下必须处理丢失的 FOLDER 节点):

namespace CBMI.Common
{
    public static class Extensions
    {
    public static string SafeGetAttributeValue(this XElement element, string attribute)
    {
        return (element != null) ?
          (element.Attribute(attribute) != null) ? 
              element.Attribute(attribute).Value : null : null;
    }
}
}
private long processFile(StreamWriter oWriter, string inFileName)
    {
        XDocument xmlDoc = XDocument.Load(inFileName);
        List<DocMetaData> docList =
            (from d in xmlDoc.Descendants("DOCUMENT")
             select new DocMetaData
             {
                 File = d.Element("FILE").Attribute("filename").Value
                 ,
                 ItemID = d.Elements("INDEX")
                    .Where(i => i.Attribute("name").Value == "Item ID(idmId)")
                    .First()
                    .Attribute("value").Value
                 ,
                 Comment = d.Elements("INDEX")
                    .Where(i => i.Attribute("name").Value == "Comment(idmComment)")
                    .First()
                    .Attribute("value").Value
                 ,
                 Title = d.Elements("INDEX")
                    .Where(i => i.Attribute("name").Value == "Title(idmName)")
                    .First()
                    .Attribute("value").Value
                 ,
                 DocClass = d.Elements("INDEX")
                    .Where(i => i.Attribute("name").Value == "Document Class(idmDocType)")
                    .First()
                    .Attribute("value").Value
                 ,
                 Folder = d.Element("FOLDER").SafeGetAttributeValue("name")
             }
            ).ToList<DocMetaData>();
        OutputListToFile(oWriter, docList);
        return docList.LongCount();
    }

I'm a rookie with LINQ to XML and I've got this code that works (most of the time):

private long processFile(StreamWriter oWriter, string inFileName)
    {
        XDocument xmlDoc = XDocument.Load(inFileName);
        List<DocMetaData> docList =
            (from d in xmlDoc.Descendants("DOCUMENT")
             select new DocMetaData
             {
                 Folder = d.Element("FOLDER").Attribute("name").Value
                 ,
                 File = d.Element("FILE").Attribute("filename").Value
                 ,
                 Comment = d.Elements("INDEX")
                    .Where(i => i.Attribute("name").Value == "Comment(idmComment)")
                    .First()
                    .Attribute("value").Value
                 ,
                 Title = d.Elements("INDEX")
                    .Where(i => i.Attribute("name").Value == "Title(idmName)")
                    .First()
                    .Attribute("value").Value
                 ,
                 DocClass = d.Elements("INDEX")
                    .Where(i => i.Attribute("name").Value == "Document Class(idmDocType)")
                    .First()
                    .Attribute("value").Value
             }
            ).ToList<DocMetaData>();
        OutputListToFile(oWriter, docList);
        return docList.LongCount();
    }

This fails on line 117 (the select expression) with:

    System.NullReferenceException: Object reference not set to an instance of an object.
   at CBMI.WinFormsUI.GridForm.<processFile>b__3(XElement d) in C:\ProjectsVS2010\CBMI.LatitudePostConverter\CBMI.LatitudePostConverter\CBMI.WinFormsUI\GridForm.cs:line 117
   at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
   at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
   at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
   at CBMI.WinFormsUI.GridForm.processFile(StreamWriter oWriter, String inFileName) in C:\ProjectsVS2010\CBMI.LatitudePostConverter\CBMI.LatitudePostConverter\CBMI.WinFormsUI\GridForm.cs:line 115
   at CBMI.WinFormsUI.GridForm.btnProcess_Click(Object sender, EventArgs e) in C:\ProjectsVS2010\CBMI.LatitudePostConverter\CBMI.LatitudePostConverter\CBMI.WinFormsUI\GridForm.cs:line 85

The data is well-formed XML. There are many <DOCUMENT> nodes in this given XML file and most but not all, <DOCUMENT> nodes contain a <FOLDER> node. I discovered this by brute force opening the XML file with VStudio 2010 and using Find command which gives counts of matching lines.

Is there a way I can improve the LINQ such that it does not fail when the data is not perfect? And, is there a way to see which part of the LINQ expression is actually failing (I'm guessing that it is due to the missing <FOLDER> nodes but that could be wrong and is an ugly brute force way to troubleshoot).

Here is one <DOCUMENT> that DOES contain the proper <FOLDER> node (at the very bottom):

    <?xml version="1.0" ?>
<DOCUMENTCOLLECTION>
<DOCUMENT>
<FILE filename="P:\LatitudeConsulting\LatConConverter-1.8.2\ConverterOutput\B0000002\3rd Party CON\D003694452.0001.tif" 
      outputpath="P:\LatitudeConsulting\LatConConverter-1.8.2\ConverterOutput\B0000002\3rd Party CON"/>
<ANNOTATION filename=""/>
<INDEX name="Access Level(idmAccessLevel)" value="Admin"/>
<INDEX name="Added By Group(idmAddedByGroup)" value="General Users"/>
<INDEX name="Added By User(idmDocOwner)" value="Import"/>
<INDEX name="Allow Secondary Version Lines?(idmDocVariants)" value="Yes"/>
<INDEX name="Application(idmVerApplication)" value=""/>
<INDEX name="Archive Category(idmDocDispCategory)" value="Archive"/>
<INDEX name="Archive Date(idmVerDispDate)" value=""/>
<INDEX name="Archive Repository(idmVerDispId)" value=""/>
<INDEX name="ArchivedDocument" value="NO"/>
<INDEX name="Availability Status(idmVerAvailStat)" value="Online"/>
<INDEX name="CAN(idmDocCustom4)" value=""/>
<INDEX name="Checked In By Group(idmVerCheckinGroup)" value="General Users"/>
<INDEX name="Checked In By User(idmVerCheckinUser)" value="Import"/>
<INDEX name="Checked Out?(idmVerCheckoutPending)" value="No"/>
<INDEX name="Checkin Date(idmVerCreateDate)" value="3/9/2001 9:20:38 AM"/>
<INDEX name="Child Count(idmVerCD)" value="0"/>
<INDEX name="Comment(idmComment)" value="1983\06_June_Meeting"/>
<INDEX name="Comment(idmVerComment)" value=""/>
<INDEX name="Content Search Repository(idmVerCsiId)" value=""/>
<INDEX name="Current Content Srch Repository(idmDocCurVerCsiId)" value=""/>
<INDEX name="Current Version Author(idmAddedByUser)" value="Import"/>
<INDEX name="Current Version Checked Out?(idmDocCurVerCheckedOut)" value="No"/>
<INDEX name="Current Version Date(idmDocCurVerDate)" value="3/9/2001 9:20:38 AM"/>
<INDEX name="Current Version ID(idmDocCurVerNum)" value="1"/>
<INDEX name="Current Version Index ID(idmDocCurVerCsiCid)" value=""/>
<INDEX name="Date Added(idmDateAdded)" value="3/9/2001 9:20:37 AM"/>
<INDEX name="Default Index Versions?(idmDocCsiDefault)" value="No"/>
<INDEX name="DiagnosticID(idmDocCustom5)" value="2-16.MDB-00015"/>
<INDEX name="Document Class(idmDocType)" value="3rd Party CON"/>
<INDEX name="Encrypted File Name(idmVerShelfFileId)" value="_276no__.__1"/>
<INDEX name="ExternalDocument" value="NO"/>
<INDEX name="File Name" value="51099.TIF"/>
<INDEX name="File Name(idmVerFileName)" value="51099.TIF"/>
<INDEX name="File Size(idmVerFileSize)" value="1166770"/>
<INDEX name="Has Annotations?(idmAnnotation)" value=""/>
<INDEX name="Index ID(idmVerCsiCid)" value=""/>
<INDEX name="Indexed Version Limit(idmDocCsiLimit)" value="1"/>
<INDEX name="Indexing Status(idmVerCsiStatus)" value="Not Indexed"/>
<INDEX name="Item ID(idmId)" value="003694452"/>
<INDEX name="Item ID(idmVerDocId)" value="003694452"/>
<INDEX name="Keyword(idmDocKeywords)" value=""/>
<INDEX name="Last Access Date(idmDateAccessed)" value="11/28/2003 3:05:30 PM"/>
<INDEX name="Last Access Date(idmDateModified)" value="8/24/2011 5:52:34 PM"/>
<INDEX name="Last Access Group(idmVerLastGroup)" value="Administrators"/>
<INDEX name="Last Access User(idmModifiedByUser)" value="Admin"/>
<INDEX name="Last Accessed Version(idmDocLastVerId)" value="1"/>
<INDEX name="Latest Version?(idmVerBranchCurVer)" value="Yes"/>
<INDEX name="Merge-Destination Version ID(idmVerMergeDst)" value="0"/>
<INDEX name="Merge-Source Version ID(idmVerMergeSrc)" value="0"/>
<INDEX name="MimeType" value="image/tiff"/>
<INDEX name="Min Item Delete Access Level(idmDocDeleteAccess)" value=""/>
<INDEX name="Modification Date(idmVerFileDate)" value="12/19/2000 11:12:30 AM"/>
<INDEX name="Number of Indexed Versions(idmDocCsiCount)" value="0"/>
<INDEX name="Offline Location(idmVerOfflineLocation)" value=""/>
<INDEX name="Online Disk Space(idmDocOnlineSize)" value="1166770"/>
<INDEX name="Online Limit(idmDocOnlineLimit)" value="5"/>
<INDEX name="Online Version Count(idmDocOnlineCount)" value="1"/>
<INDEX name="Origin ID(idmDocOriginID)" value=""/>
<INDEX name="Origin Library(idmDocOriginLibrary)" value=""/>
<INDEX name="Original File Name(idmDocOriginalFile)" value="51099.TIF"/>
<INDEX name="Permanent Index?(idmVerCsiPermanent)" value="No"/>
<INDEX name="Permanent Version?(idmVerPermanent)" value="No"/>
<INDEX name="Property ID(idmDocDynPropertyId)" value=""/>
<INDEX name="Protected?(idmDocProtected)" value="Yes"/>
<INDEX name="Publishing Status(idmPublish)" value=""/>
<INDEX name="Reclaim Pending?(idmVerReclaimPending)" value=""/>
<INDEX name="Reclaim Submitted Date(idmVerReclaimDate)" value=""/>
<INDEX name="Replica?(idmDocIsReplica)" value="No"/>
<INDEX name="ReplicatedDocument" value="NO"/>
<INDEX name="Secondary Version Line Count(idmVerBranchCount)" value="0"/>
<INDEX name="Source Version Checkout Date(idmVerPrevCheckoutDate)" value=""/>
<INDEX name="Storage Category(idmDocFileCategory)" value="Documents"/>
<INDEX name="Storage Repository(idmVerShelfId)" value="2"/>
<INDEX name="Title(idmName)" value="3rd Party CON Comments"/>
<INDEX name="Version ID(idmVerId)" value="1"/>
<FOLDER name="/NACAIE/1983/06_June_Meeting/NAPNSC"/>
</DOCUMENT>

EDIT: solution follows (contains LINQ that fixed this problem when FOLDER node might be missing; use of First() might be dangerous practice as others note but in this case missing FOLDER nodes had to be handled):

namespace CBMI.Common
{
    public static class Extensions
    {
    public static string SafeGetAttributeValue(this XElement element, string attribute)
    {
        return (element != null) ?
          (element.Attribute(attribute) != null) ? 
              element.Attribute(attribute).Value : null : null;
    }
}
}
private long processFile(StreamWriter oWriter, string inFileName)
    {
        XDocument xmlDoc = XDocument.Load(inFileName);
        List<DocMetaData> docList =
            (from d in xmlDoc.Descendants("DOCUMENT")
             select new DocMetaData
             {
                 File = d.Element("FILE").Attribute("filename").Value
                 ,
                 ItemID = d.Elements("INDEX")
                    .Where(i => i.Attribute("name").Value == "Item ID(idmId)")
                    .First()
                    .Attribute("value").Value
                 ,
                 Comment = d.Elements("INDEX")
                    .Where(i => i.Attribute("name").Value == "Comment(idmComment)")
                    .First()
                    .Attribute("value").Value
                 ,
                 Title = d.Elements("INDEX")
                    .Where(i => i.Attribute("name").Value == "Title(idmName)")
                    .First()
                    .Attribute("value").Value
                 ,
                 DocClass = d.Elements("INDEX")
                    .Where(i => i.Attribute("name").Value == "Document Class(idmDocType)")
                    .First()
                    .Attribute("value").Value
                 ,
                 Folder = d.Element("FOLDER").SafeGetAttributeValue("name")
             }
            ).ToList<DocMetaData>();
        OutputListToFile(oWriter, docList);
        return docList.LongCount();
    }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

反话 2024-12-08 15:05:23

在尝试选择给定节点之前,您始终可以检查它:

Folder = (d.Element("FOLDER") != null) ? (d.Element("FOLDER").Attribute("name") != null)
                                          ? Attribute("name").Value : null
                                       : null

但我承认这可能会变得有点难看。在这种情况下,您可以创建一个 XElement 扩展方法来执行以下操作:

public static class Extensions
{
   public static string SafeGetAttributeValue(this XElement element, string attribute)
   {
      return (element != null) ? (element.Attribute(attribute) != null)
                                              ? Attribute(attribute).Value : null
                                           : null
   }
}

您可以使用以下方法:

select new DocMetaData
{
   Folder = d.Element("FOLDER").SafeGetAttributeValue("name"),
   //the rest of your object creation
}

You can always check the given node before trying to select it:

Folder = (d.Element("FOLDER") != null) ? (d.Element("FOLDER").Attribute("name") != null)
                                          ? Attribute("name").Value : null
                                       : null

But I admit that can get kind of ugly. In that case you can create an XElement extension method that does that:

public static class Extensions
{
   public static string SafeGetAttributeValue(this XElement element, string attribute)
   {
      return (element != null) ? (element.Attribute(attribute) != null)
                                              ? Attribute(attribute).Value : null
                                           : null
   }
}

Which you could use like:

select new DocMetaData
{
   Folder = d.Element("FOLDER").SafeGetAttributeValue("name"),
   //the rest of your object creation
}
不知所踪 2024-12-08 15:05:23

我无法测试这是否是您的确切问题,但如果查询中没有任何值,First() 会引发异常。您可以通过使用 FirstOrDefault() 来避免这种情况,然后检查结果是否为 null

I can't test to see if this is the exact problem for you, but First() throws an exception if there isn't any values in the query. You can avoid that by using FirstOrDefault() instead and then checking if the result is null.

离去的眼神 2024-12-08 15:05:23

我的经验法则是永远使用 First()FirstOrDefault()Single() 或 < code>SingleOrDefault() 方法位于查询中间。它应该始终是最后调用的方法。如果需要从所选项目中选择属性,请先进行投影,然后调用该方法。它将导致代码看起来更简洁,使这种情况更容易处理。

例如,

// Change this:
d.Elements("INDEX")
 .Where(i => i.Attribute("name").Value == "Comment(idmComment)")
 .First()
 .Attribute("value").Value

// to this:
d.Elements("INDEX")
 .Where(i => i.Attribute("name").Value == "Comment(idmComment)")
 .Select(i => i.Attribute("value").Value)
 .First()

我将其重写为:

private long processFile(StreamWriter oWriter, string inFileName)
{
    XDocument xmlDoc = XDocument.Load(inFileName);
    List<DocMetaData> docList = xmlDoc.Descendants("DOCUMENT")
        .Select(e => new
        {
            Folder = (string)e.Element("FOLDER").Attribute("name"),
            File = (string)e.Element("FILE").Attribute("filename"),
            Comment = (string)e.Elements("INDEX")
                .Where(i => (string)i.Attribute("name") == "Comment(idmComment)")
                .Select(i => (string)i.Attribute("value"))
                .FirstOrDefault(),
            Title = (string)e.Elements("INDEX")
                .Where(i => (string)i.Attribute("name") == "Title(idmName)")
                .Select(i => (string)i.Attribute("value"))
                .FirstOrDefault(),
            DocClass = (string)e.Elements("INDEX")
                .Where(i => (string)i.Attribute("name") == "Document Class(idmDocType)")
                .Select(i => (string)i.Attribute("value"))
                .FirstOrDefault(),
        })
        .ToList();
    OutputListToFile(oWriter, docList);
    return docList.LongCount();
}

My rule of thumb is to never use the First(), FirstOrDefault(), Single() or SingleOrDefault() methods in the middle of the query. It should always be the last method that is called. If you need to select a property from the selected item, project first, then call the method. It will lead to cleaner looking code making situations like this a whole lot easier to deal with.

e.g.,

// Change this:
d.Elements("INDEX")
 .Where(i => i.Attribute("name").Value == "Comment(idmComment)")
 .First()
 .Attribute("value").Value

// to this:
d.Elements("INDEX")
 .Where(i => i.Attribute("name").Value == "Comment(idmComment)")
 .Select(i => i.Attribute("value").Value)
 .First()

I'd rewrite it as this:

private long processFile(StreamWriter oWriter, string inFileName)
{
    XDocument xmlDoc = XDocument.Load(inFileName);
    List<DocMetaData> docList = xmlDoc.Descendants("DOCUMENT")
        .Select(e => new
        {
            Folder = (string)e.Element("FOLDER").Attribute("name"),
            File = (string)e.Element("FILE").Attribute("filename"),
            Comment = (string)e.Elements("INDEX")
                .Where(i => (string)i.Attribute("name") == "Comment(idmComment)")
                .Select(i => (string)i.Attribute("value"))
                .FirstOrDefault(),
            Title = (string)e.Elements("INDEX")
                .Where(i => (string)i.Attribute("name") == "Title(idmName)")
                .Select(i => (string)i.Attribute("value"))
                .FirstOrDefault(),
            DocClass = (string)e.Elements("INDEX")
                .Where(i => (string)i.Attribute("name") == "Document Class(idmDocType)")
                .Select(i => (string)i.Attribute("value"))
                .FirstOrDefault(),
        })
        .ToList();
    OutputListToFile(oWriter, docList);
    return docList.LongCount();
}
醉生梦死 2024-12-08 15:05:23

在您的 linq 查询中,在每个可能为空的字段上,因此如果您对它们进行赋值,则会抛出异常,您可以:

MyDone = PossibleNullNode != null ? PossibleNullNode.Value : WhateverFloatsYourBoat

In your linq query, on every fields that might be null, hence throwing an exception if you .Value them, you could :

MyDone = PossibleNullNode != null ? PossibleNullNode.Value : WhateverFloatsYourBoat
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文