无法访问或查找对System.Xml.Linq.LineInfoAnnotation的引用。为什么是这样?

时间:2018-04-06 17:51:56

标签: c# xml linq xelement

我有一个应用程序,它接受XML文档并按某些属性对其进行排序。我有与XML文档的每一行相关的信息,我希望将其包含在已排序的文档中。为此,

当我加载文件时,我确保使用 XDocument.Load(file,LoadOptions.SetLineInfo)加载行信息。

然后我递归迭代每个XElement并获取其行信息。当我运行应用程序时,我注意到每个XElement都有两个注释,

  • 类型 System.Xml.Linq.LineInfoAnnotation
  • 之一
  • 和类型 System.Xml.Linq.LineInfoEndElementAnnotation 之一。

它们包含我需要的信息,但在私人领域。

我找不到关于这些类的任何信息,我无法实例化它们,它们不会出现在 System.Xml.Linq 下的对象浏览器中。然而它们存在,我可以对它们运行“GetType()”并获取有关该类的信息。

如果它们存在,为什么它们不在MSDN引用中,为什么我不能实例化它们或扩展它们?为什么我不能在对象浏览器中找到它们?

P.S。 我的解决方法是使用反射来获取每个元素中包含的信息。但我仍然无法传递类名来告诉方法它是什么类型,我必须将对象与XElement.Annotations(typeof(object))隔离,然后在其上运行GetType()。我在下面说明了这一点。

public object GetInstanceField(Type type, object instance, string fieldName)
{
 //reflective method that gets value of private field
}

XElement xEl = existingXElement;    //existingXElement is passed in

var annotations = xEl.Annotations(typeof(object)); //contains two objects, start and end LineInfoAnnotation
var start = annotations.First(); 
var end = annotations.Last(); 

var startLineNumber = GetInstanceField(start.GetType(), start, lineNumber);  //lineNumber is private field I'm trying to access.
var endLineNumber = GetInstanceField(end.GetType(), end, lineNumber);

这段代码有效,但我再说一遍,我不能告诉方法“typeof(LineInfoAnnotation)”,而是要在现有对象上做GetType。我无法理解这一点。

1 个答案:

答案 0 :(得分:2)

这些类是私有的 - 如果你愿意的话,这是一个实现细节。

所有XObjects(元素,属性)都实现IXmlLineInfo接口 - 但它们显式实现了接口,因此您必须执行强制转换来访问属性。

获得IXmlLineInfo后,您可以使用属性LineNumberLinePosition

var data = 
@"<example>
<someElement
  someAttribute=""val"">

  </someElement></example>
";

var doc = XDocument.Load(new MemoryStream(Encoding.UTF8.GetBytes(data)), LoadOptions.SetLineInfo);
foreach(var element in doc.Descendants()) {
    var elLineInfo = element as IXmlLineInfo;
    Console.Out.WriteLine(
        $"Element '{element.Name}' at {elLineInfo.LineNumber}:{elLineInfo.LinePosition}");


    foreach(var attr in element.Attributes()) {
        var attrLineInfo = attr as IXmlLineInfo;
        Console.Out.WriteLine(
            $"Attribute '{attr.Name}' at {attrLineInfo.LineNumber}:{attrLineInfo.LinePosition}");
    }
}

输出:

Element 'example' at 1:2
Element 'someElement' at 2:2
Attribute 'someAttribute' at 3:3

要获取EndElement信息,您必须使用普通的旧XML阅读器,因为XObject api不会公开有关元素结束位置的任何信息。

using(var reader = doc.CreateReader()) {    
    while(reader.Read()) {
        var lineInfo = reader as IXmlLineInfo;
        Console.Out.WriteLine($"{reader.NodeType} {reader.Name} at {lineInfo.LineNumber}:{lineInfo.LinePosition}");

        if(reader.NodeType == XmlNodeType.Element && reader.HasAttributes) {
            while(reader.MoveToNextAttribute()) {
                Console.Out.WriteLine($"{reader.NodeType} {reader.Name} at {lineInfo.LineNumber}:{lineInfo.LinePosition}");
            }
        }
    }   
}

输出:

Element example at 1:2
Element someElement at 2:2
Attribute someAttribute at 3:3
EndElement someElement at 5:5
EndElement example at 5:19