- ベストアンサー
C#のXmlDocumentについての質問
- C#のXmlDocumentについての質問です。
- 上記のコードでは、XmlDocumentのGetElementsByTagNameメソッドを使用して特定の要素を取得し、その結果をXmlNodeオブジェクトとして取得しています。
- しかし、Console.WriteLineメソッドを使用してnodeObjを出力すると、型がXmlElementとして表示されます。なぜ同じオブジェクトでも出力結果と型が異なるのでしょうか?
- みんなの回答 (5)
- 専門家の回答
質問者が選んだベストアンサー
> なぜ、Itemメソッドが参照が指すインスタンスがXmlElementクラスのオブジェクトなのに > 親クラスのオブジェクトとして帰ってくるのかは私にはわかりませんが 戻り値の型が単純にXmlNode型だからですね。 XmlNodeList型がXmlNodeのリストなので,Itemの戻り値をXmlElementとすることができません。 例えば,XmlNode.SelectNodesのXPath式で,/@attrのように属性を指定すればXmlNodeListの中にはXmlAttributeが入りますし,/text()を指定すればXmlTextが入ります。 references) XmlNodeList.Item メソッド (System.Xml) http://msdn.microsoft.com/ja-jp/library/System.Xml.XmlNodeList.Item XmlNode.SelectNodes メソッド (String) (System.Xml) http://msdn.microsoft.com/ja-jp/library/hcebdtae なお,Undocumentedですが,XmlDocument.GetElementsByTagNameの戻り値の型は, XmlNodeListを継承した,internalなクラスであるSystem.Xml.XmlElementList型になっています。 ただし,Itemの戻り値はXmlNodeのままになっています。 # .NET 4の参照ソースによる reference) Microsoft Reference Source Server http://referencesource.microsoft.com/ > GetType().FullNameというのは参照先のインスタンスのクラス名であって > 変数の型(クラス名)は一切関係ないんですね。ちょっとごっちゃになっていました。 正確に言うと,GetType()の戻り値がインスタンスのTypeだからですね。 Object.GetTypeは「インスタンスの型」を表すSystem.Typeを返します。 今回の場合,nodeObj.GetType() == typeof(XmlElement)は真です。 reference) Object.GetType メソッド (System) http://msdn.microsoft.com/ja-jp/library/System.Object.GetType
その他の回答 (4)
- WebSurfer
- ベストアンサー率55% (33/59)
> これは,オブジェクトの実際の型に依存し,式中での型に依存しません。 そういうことを言っているわけではなくて、XmlNode.ToString() や XmlNode.GetType().FullName が、"System.Xml.XmlNode" ではなくて、 "System.Xml.XmlElement" を返すということを言っているのですが。 ちなみに、typeof(XmlNode).FullName は "System.Xml.XmlNode" と完 全限定名を返します。 なお、「完全限定名」と「完全修飾名」は、もとは Fully Qualified Type Name で、単に日本語訳の違いのようです。MSDN ライブラリの Object.ToString メソッドの説明は、.NET 3.5 では 「完全限定名」 .NET 4 から「完全修飾名」になってます。一つのページで両方使って いるものもあります(例:下記 URL)。(笑)
- Yune-Kichi
- ベストアンサー率74% (465/626)
> XmlNode型の変数のnodeObjには実際には本来はXmlElementクラスのインスタンスが > XmlNodeクラスにアップキャストされてnodeObjという変数に格納されているということでしょうか? アップキャストといえばアップキャストですね。 キャストの要らない変換の範囲なので,親クラスへの変換はキャストするとはあまり言いませんが……。 より詳しく言うなら,XmlNodeListはその名の通り,XmlNodeのコレクションです。 なので,GetElementsByTagNameで見つかったXmlElementがXmlNode型としてXmlNodeListのコレクションに代入されています。 そして,Itemメソッドの戻り値が既にXmlNode型になっています。 このあたりは,.NET 2.0以降であればIEnuemrable<XmlElement>あたりを返すような実装になったかもしれませんが, XmlDocumentがそもそも.NET 1.0のジェネリクスのない時代からのものであることもあって, 独自の(型付けされた)コレクション型を用意しているということがあると思います。 # .NET 3.5で追加されたSystem.Xml.Linq.XDocument.Descendantsなどは,IEnumerable<XElement>を返します。 ちなみに…… > MSDN ライブラリには Object.ToString メソッドの既定の実装は、Object > の型の完全限定名(下記 URL 参照)を返しますとありますが、Object は > そうでも、XmlNode, XmlElement は違うようです。 MSDNにあるのは, > Its ToString method returns the object's fully qualified type name. です。System.Objectの完全修飾名ではなく,「そのオブジェクト」の型の完全修飾名です。 これは,オブジェクトの実際の型に依存し,式中での型に依存しません。 System.Object型の変数にSystem.Xml.XmlElement型のオブジェクトを代入しても, オブジェクトの型はSystem.Xml.XmlElementであるため,デフォルトの実装はSystem.Xml.XmlElementを返します。 ref) http://msdn.microsoft.com/en-us/library/system.object.tostring http://msdn.microsoft.com/ja-jp/library/system.object.tostring
- WebSurfer
- ベストアンサー率55% (33/59)
> Console.WriteLine(nodeObj); > の箇所の出力で〔XmlElement〕という内容が出力されたのでしょうか? nodeObj.ToString() で取得できる文字列が "System.Xml.XmlElement" に なっている(理由は知りませんが Microsoft がそう設定した)という単 純な理由からだと思います。 型名を取得できるわけではありません。 ちなみに、XmlNode.ToString() も XmlElement.ToString() も返される文 字列は同じ "System.Xml.XmlElement" になります。 MSDN ライブラリには Object.ToString メソッドの既定の実装は、Object の型の完全限定名(下記 URL 参照)を返しますとありますが、Object は そうでも、XmlNode, XmlElement は違うようです。
- Yune-Kichi
- ベストアンサー率74% (465/626)
System.Object.ToStringはthis.GetType().FullNameを出力します。 そして,XmlElemenetクラスやその先祖クラスはToStringをオーバーライドしません。 このため,System.Xml.XmlElementと出力されます。
補足
早速の回答ありがとうございます。 すこし、理解がおいつきません。 マニュアルをみるとXML系の継承階層は以下のようです。 System.Object System.Xml.XmlNode System.Xml.XmlLinkedNode System.Xml.XmlElement XmlNode型の変数のnodeObjには実際には本来はXmlElementクラスのインスタンスが XmlNodeクラスにアップキャストされてnodeObjという変数に格納されているということでしょうか?
補足
回答ありがとうございます。 自分なりにしらべてみましたが if( nodeObj is XmlElement){ } とするとどうもtrueが帰ってきているようなのでnodeObjの中にある参照が指し示す インスタンス自身はあくまでXmlElementクラスのオブジェクトということですね。 なぜ、Itemメソッドが参照が指すインスタンスがXmlElementクラスのオブジェクトなのに 親クラスのオブジェクトとして帰ってくるのかは私にはわかりませんが GetType().FullNameというのは参照先のインスタンスのクラス名であって 変数の型(クラス名)は一切関係ないんですね。ちょっとごっちゃになっていました。