オブジェクトをTにキャストします


91

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

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

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

回答:


207

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

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

1
Convert.ChangeTypeの行を次のように変更しました: 'return(T)Convert.ChangeType(readData、typeof(T)、System.Globalization.CultureInfo.InstalledUICulture.NumberFormat)さまざまな異なるカルチャ構成で機能するようにしました。
Kasper Holdum 2009

2
これが正解です。しかし、ここではtry / catchが完全に冗長であると主張することができます。特にミュートされた例外を考慮します。if(readData is T){...}の部分で十分だと思います。
pim

変換する前に、readDateがnullかどうかを確認できます。その場合はdefault(T)を返します。
マヌエルコッホ

「オブジェクトはIConvertibleを実装する必要があります」というメッセージが表示されます。
ケーシークルックストン

19

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));
}

私は最初にConvert.ChangeTypeを調べましたが、何らかの奇妙な理由でこの操作には役立たないと判断しました。あなたとボブは両方とも同じ答えを提供しました、そして私はあなたの答えを混ぜて行くことに決めたので、私はtryステートメントの使用を避けましたが、可能な場合は「return(T)readData」を使用しました。
Kasper Holdum 2009年


3

型を参照型にする必要があります:

 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

実際、ここでの問題は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;
}

かなりコンパクトでエレガントに見えます。ただし、受け入れられた回答のソリューションは、IFormatProviderを受け入れるため、複数の異なるカルチャと互換性のあるChangeTypeを使用します。これはプロジェクトの必需品なので、私はその解決策を守ります。
Kasper Holdum 2009

2

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


1

'class'制約を追加します(または、実行された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呼び出しを実行すると、実際に何かが達成されるかどうかはわかりません。実際には、例外を生成することによって処理オーバーヘッドが増加する可能性があります。やりがいのある違いを誰かが知っているなら、投稿してください!

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.