web-dev-qa-db-ja.com

Tへのオブジェクトのキャスト

.NETでXmlReaderクラスを使用してXMLファイルを解析していますが、さまざまな属性を一般的に読み取るための汎用解析関数を記述するのが賢明だと思いました。私は次の機能を思いつきました:

private static T ReadData<T>(XmlReader reader, string value)
{
    reader.MoveToAttribute(value);
    object readData = reader.ReadContentAsObject();
    return (T)readData;
}

私が気づいたように、これは私が計画したように完全に機能しません。キャストはintから数値型に変換できないため、doublestringなどのプリミティブ型ではエラーがスローされます。私の機能が修正された形式で勝つ方法はありますか?

75
Kasper Holdum

まず、キャストできるかどうかを確認します。

if (readData is T) {
    return (T)readData;
} 
try {
   return (T)Convert.ChangeType(readData, typeof(T));
} 
catch (InvalidCastException) {
   return default(T);
}
182
Bob

Convert.ChangeType を試しましたか?

メソッドが常に文字列を返す場合、それは奇妙ですが、それはポイントのほかですが、おそらくこの変更されたコードはあなたが望むことをするでしょう:

private static T ReadData<T>(XmlReader reader, string value)
{
    reader.MoveToAttribute(value);
    object readData = reader.ReadContentAsObject();
    return (T)Convert.ChangeType(readData, typeof(T));
}

試してみる

if (readData is T)
    return (T)(object)readData;
7
Sadegh

型は参照型である必要があります:

 private static T ReadData<T>(XmlReader reader, string value) where T : class
 {
     reader.MoveToAttribute(value);
     object readData = reader.ReadContentAsObject();
     return (T)readData;
 }

次に、値型とTryParseを使用する別の操作を行います...

 private static T ReadDataV<T>(XmlReader reader, string value) where T : struct
 {
     reader.MoveToAttribute(value);
     object readData = reader.ReadContentAsObject();
     int outInt;
     if(int.TryParse(readData, out outInt))
        return outInt
     //...
 }
3
Tom Ritter

実際、ここでの問題はReadContentAsObjectの使用です。残念ながら、この方法は期待どおりではありません。値の最も適切なタイプを検出する必要がありますが、実際には文字列を返します(これはReflectorを使用して確認できます)。

しかし、あなたの特定のケースでは、あなたはすでにあなたがキャストしたい型を知っているので、間違った方法を使用していると言います。

代わりにReadContentAsを使用してみてください。まさに必要なものです。

private static T ReadData<T>(XmlReader reader, string value)
{
    reader.MoveToAttribute(value);
    object readData = reader.ReadContentAs(typeof(T), null);
    return (T)readData;
}
3
baretta

おそらく、文字列からTに変換するデリゲートをパラメーターとして渡すことができます。

2
ChrisW

「クラス」制約を追加します(または、実行されるTオブジェクトの基本クラスまたはインターフェイスのような、より詳細な)。

_private static T ReadData<T>(XmlReader reader, string value) where T : class
{
    reader.MoveToAttribute(value);
    object readData = reader.ReadContentAsObject();
    return (T)readData;
}
_

または_where T : IMyInterface_またはwhere T : new()など

1

実際、応答には興味深い質問があります。これは、エラーが発生した場合に関数に実行させたいことです。

たぶん、Tに読み込もうとするTryParseメソッドの形式で構築する方が理にかなっていますが、実行できない場合はfalseを返しますか?

    private static bool ReadData<T>(XmlReader reader, string value, out T data)
    {
        bool result = false;
        try
        {
            reader.MoveToAttribute(value);
            object readData = reader.ReadContentAsObject();
            data = readData as T;
            if (data == null)
            {
                // see if we can convert to the requested type
                data = (T)Convert.ChangeType(readData, typeof(T));
            }
            result = (data != null);
        }
        catch (InvalidCastException) { }
        catch (Exception ex)
        {
            // add in any other exception handling here, invalid xml or whatnot
        }
        // make sure data is set to a default value
        data = (result) ? data : default(T);
        return result;
    }

編集:今私はそれについて考えると、私は本当にconvert.changetypeテストを行う必要がありますか? as行は既にそれをしようとしませんか?追加のchangetype呼び出しを実行しても、実際に何が達成されるかはわかりません。実際には、例外を生成するだけで処理のオーバーヘッドが増加する場合があります。誰かがやりがいのある違いを知っているなら、投稿してください!

1
genki