DOBON.NET DOBON.NETプログラミング掲示板過去ログ

generic関数内で型の変換方法について

環境/言語:[XP, C#]
分類:[.NET]

お世話になります。
generic関数を作り、その中で指定した型への型変換を実施したいのですが、どのようにすればいいでしょうか。
以下のようなイメージです。

void MakeHoge<T>() where T:new()
{
T tt= new T();
string c = "10";
tt=T.Parse(c);
//その他の処理が以下に続きます。

}

Parseのところで以下のようなメッセージがでてしまいます。
'T'は型パラメータですが、指定されたコンテキストでは有効では有りません。

TにはInt32やDecimalなど、Parseを実装するものを指定する予定です。
どのようにすれば型の変換がうまくできますでしょうか。

以上、よろしくお願いします。
Parseは各型独自に実装なのでReflectionで見ないと駄目かと思います。
2010ならdynamic使えば結構楽

        private void Proc1<T>()
        {
            T tt;

            Type tpA = typeof(T);
            System.Reflection.MethodInfo Parse = tpA.GetMethod("Parse", (System.Reflection.BindingFlags)
                                    System.Reflection.BindingFlags.Static |
                                    System.Reflection.BindingFlags.Public |
                                    System.Reflection.BindingFlags.InvokeMethod,null,new Type[] {typeof(string)},null);
            if (Parse == null)
            {
                throw new Exception(tpA.FullName + "にはParseがありません。");
            }
            tt = (T)Parse.Invoke(tpA, new object[] { "10" });
        }
2010/12/30(Thu) 15:30:50 編集(投稿者)

■No27918に返信(あーしゃんさんの記事)
> お世話になります。
> generic関数を作り、その中で指定した型への型変換を実施したいのですが、どのようにすればいいでしょうか。
> 以下のようなイメージです。

C#のバージョンは?2.0(VC#2005)、3.0(VC#2008)、4.0(VC#2010)のどれでしょうか?
どのバージョンにしてもイメージのようなことズバリはできません。

> void MakeHoge<T>() where T:new()
> {
> T tt= new T();
> string c = "10";
> tt=T.Parse(c);
> //その他の処理が以下に続きます。
>
> }

型Tに関して呼び出せるメソッドは限定的です。
(1) どのクラスも必ずObjectを継承しているのでToStringメソッドなどのObjectが持つメソッドは呼び出せますが、それ以外のメンバーはそもそも呼び出せません。

(2) whereを使って型Tに制約を付けて、例えば、IEnumerableインターフェースを実装していること、という制約を付けると、IEnumerableインタフェースが持つメソッドならば呼び出せるようになります。

(1)、(2)のいずれかのパターンに当てはまらないメソッドは基本的に呼び出せません。
※ C#4.0であれば、(2)のように制約を付けられない場合でも、dynamicキーワードを利用して強引に任意のインスタンスメソッドを呼び出すことはできます。

> Parseのところで以下のようなメッセージがでてしまいます。
> 'T'は型パラメータですが、指定されたコンテキストでは有効では有りません。

Int32.Parseメソッドのようなstaticメソッドを型T経由で呼び出す手段はありません。

<追記>
時間がかかっている間に良回答が…
リフレクションを使えばできなくはないですねorz リフレクションのことは検討対象からはずれてました
</追記>
訂正:
dynamicだとStaticメンバへのアクセスが出来ないので
dynamicを使っても駄目です。
■No27918に返信(あーしゃんさんの記事)
> generic関数を作り、その中で指定した型への型変換を実施したいのですが、
オーバーロードで対応した方が良いのかも知れない。

> T tt= new T();
> string c = "10";
> tt=T.Parse(c);
その昔、今は亡き某所でこんな回答をしたことが。

string c = "10";
T ttt = Microsoft.VisualBasic.CompilerServices.Conversions.ToGenericParameter<T>(c);
■No27919に返信(shuさんの記事)
> throw new Exception(tpA.FullName + "にはParseがありません。");

メンバー無しなら、MissingMethodException の方が適切かと思います。
となれば、直接呼び出してしまうのも一つの手かも。

T ttt = (T)typeof(T).InvokeMember("Parse", BindingFlags.InvokeMethod, null, null, new object[] { c });
■No27923に返信(魔界の仮面弁士さんの記事)
> ■No27919に返信(shuさんの記事)
>>throw new Exception(tpA.FullName + "にはParseがありません。");
>
> メンバー無しなら、MissingMethodException の方が適切かと思います。
> となれば、直接呼び出してしまうのも一つの手かも。
>
> T ttt = (T)typeof(T).InvokeMember("Parse", BindingFlags.InvokeMethod, null, null, new object[] { c });

なるほど、これの方がすっきり書けますね。
皆様
多くのコメント、ありがとうございました。
魔界さんの方法にて無事に目的の機能を実現できました。
大変助かりました。
ありがとうございましたm(__)m
クローズしますm(__)m。
解決済み!

DOBON.NET | プログラミング道 | プログラミング掲示板