プロが教えるわが家の防犯対策術!

C#のXmlDocumentについて質問です。
using System;
using System.Xml;
using System.Windows;
public class XmlNewClass{
public static void Main(String [] args){

XmlDocument xmlObj = new XmlDocument();
xmlObj.Load("./test.xml");


XmlNode nodeObj = xmlObj.GetElementsByTagName("root").Item(0);

Console.WriteLine(nodeObj);

}
}


上記のようなコードがあったとします。
この場合、プロンプトに表示されるないようは
〔System.Xml.XmlElement〕という記述が出力されます。

次に
XmlElement elementObj =nodeObj;
というコードを追加したとします。
それを実行してみると

/******************************************************************
xml.cs(21,26): error CS0266: 型 'System.Xml.XmlNode' を 'System.Xml.XmlElement'
に暗黙的に変換できません。明示的な変換が存在します。(cast
が不足していないかどうかを確認してください)
***************************************************************************/
というようなエラーがプロンプト上に表示されます。

これはnodeObjがXmlNodeというクラスだということですが
(実際GetElementsByTagNameで帰って来るオブジェクトはXmlNodeというクラスだとマニュアルにも記載がありました)
なぜ冒頭のコードで
Console.WriteLine(nodeObj);
の箇所の出力で〔XmlElement〕という内容が出力されたのでしょうか?
同じオブジェクトなのに、なぜ出力と型がことなるのでしょうか?

ご教授よろしくお願いします。

A 回答 (5件)

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という変数に格納されているということでしょうか?

補足日時:2012/10/11 08:07
    • good
    • 0

> 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 は違うようです。

参考URL:http://msdn.microsoft.com/ja-jp/library/aa691137 …
    • good
    • 0

> 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.o … http://msdn.microsoft.com/ja-jp/library/system.o …

この回答への補足

回答ありがとうございます。

自分なりにしらべてみましたが 


if( nodeObj is XmlElement){
}
とするとどうもtrueが帰ってきているようなのでnodeObjの中にある参照が指し示す
インスタンス自身はあくまでXmlElementクラスのオブジェクトということですね。

なぜ、Itemメソッドが参照が指すインスタンスがXmlElementクラスのオブジェクトなのに
親クラスのオブジェクトとして帰ってくるのかは私にはわかりませんが
GetType().FullNameというのは参照先のインスタンスのクラス名であって

変数の型(クラス名)は一切関係ないんですね。ちょっとごっちゃになっていました。

補足日時:2012/10/16 00:14
    • good
    • 0

> これは,オブジェクトの実際の型に依存し,式中での型に依存しません。



そういうことを言っているわけではなくて、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)。(笑)

参考URL:http://msdn.microsoft.com/ja-jp/library/yfsftwz6 …
    • good
    • 0

> なぜ、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.X …
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.O …
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!