C#の動的キャストに関する質問

このQ&Aのポイント
  • C#のメソッドにobjectの引数を渡して動的にキャストする場合、Typeクラスを使用してobjの型を取得し、Convert.ChangeTypeメソッドを使用して動的キャストを行うことができます。
  • しかし、多様性をもつobjectを引数にする多くの場合は、objの型が不定であるため、TypeクラスとConvert.ChangeTypeメソッドを使用した動的キャストは困難です。
  • GetMethodやGetPropertyメソッドを使用してメソッドやプロパティを取得し、InvokeやGetValue、SetValueメソッドを使用して操作することは可能ですが、ドット記法を使用した動的キャストはできません。
回答を見る
  • ベストアンサー

C#の動的キャスト

いつもお世話になっています。 C#の動的キャストに関する質問です。 C#のメソッドにobjectの引数を渡して動的にキャストする場合 void Hoge(object obj) { Type t = Type.GetType(obj); objの型 obj2 = (objの型)Convert.ChangeType(obj, t); //(1) ................................. } のようにされています。 しかし多様性をもつobjcetを引数にする多くの場合は「objの型」は不定です。 逆に言えば「objの型」がわかっている場合はわざわざobjectを引数にする必要はないわけです。 そこで質問ですが、何とかType t から「objの型」を取得して(1)記法による動的キャストを行う方法はないでしょうか? GetMethod, GetPropertyでメソッド,プロパティを取得し、Invoke, GetValue, SetValueすることは可能ですが、できればドット記法(.)が使える (1) のような動的キャストを行いたいと考えています。 よろしくお願いします。

質問者が選んだベストアンサー

  • ベストアンサー
  • dmq
  • ベストアンサー率80% (21/26)
回答No.2

そのままではT型のメソッドやプロパティを呼ぶことはできません。 Bar()やFugaはHogeに渡す型すべてに存在するのでしょうか? もしするのでしたら最大公約数的なインターフェイスを作って、 それぞれの型に実装してあげると使えるようになります。 interface HogeBase {  void Bar();  object Fuga{ get; set; } } void Hoge<T>(T obj) where T : HogeBase {  obj.Bar();  member = obj.Fuga; } Bar()やFugaはHogeに渡す型すべてに存在するのでないのなら、 少々手間が増えますがそれでも↑の応用でいけます。 (2)は型情報が要らないのなら捨ててしまっていいと思います。

kahata
質問者

お礼

ありがとうございます。 > Bar()やFugaはHogeに渡す型すべてに存在するのでしょうか? 私の場合、多くの場合objはFormの派生クラスやcoltrolで、現状の処理はobj.GetType().Nameで処理を分岐しています。(if~else, switch) > もしするのでしたら最大公約数的なインターフェイスを作って、 > それぞれの型に実装してあげると使えるようになります。 やはりこういう処理が必要になるのですね。 参考にさせていただきます。

その他の回答 (1)

  • dmq
  • ベストアンサー率80% (21/26)
回答No.1

(1)記法から外れますが、総称型を使うのはいかがでしょうか? C#3.0でしたら、型を決め打ちせずとも自動的に型推論してくれます。 void Hoge<T>(T obj) {  Type t = typeof(T); }

kahata
質問者

補足

早速 興味ある方法をありがとうございます。 もう少し教えてください このあと、objのメンバーにアクセスする方法を教えてください。 メソッド : obj.Bar() 、プロパティ: obj.Fuga でよろしいですか? void Hoge<T>(T obj) {  Type t = typeof(T); // (2) } (2)の Type t の使い方をよろしく ご教示お願いします。

関連するQ&A

  • C#で実行時にメソッドの返り値の型を変化させる

    C# で、実行時にメソッドの返り値の型を変化させることは可能でしょうか? たとえば、 public class MyData { object o; public void setValue( object a ) { o = a; } public object getValue() { return o; } } というクラスがあるとき、 static void Main(string[] args) { MyData a = new MyData(); a.setValue( 3 ); Console.WriteLine( a.getValue().GetType().ToString() ); int i = (int)a.getValue(); } というコードを実行すると、 System.Int32 と表示されます。Main の 4 行目で、(int)のキャストをはずすと、object から int への暗黙の変換はできませんというコンパイルエラーになります。 この(int)のキャストをしなくてもエラーにならないような getValue の関数はできないでしょうか? o は、数値型であるとします。 たとえば、MyData に、 public int getInt() { return (int)o; } とすれば、必ず int を返すようなメソッドはできると思うのですが、これだと、getByte() や、getDouble() などのように、考えられるすべての型を想定してメソッドを作ることになってしまいます。 そうではなく、getValue() で、少なくとも数値型の暗黙の変換はしてくれるようなことにできないでしょうか。 よろしくお願いします。

  • C#で配列のフィールドを取得したい

    C#2.0を試用しています。 次のような書き方ではプリミティブ型は取得できるのですが、 配列のフィールドは取得できないので、 なんとかして取得する方法はないのでしょうか? public class MasterClass {  public int a = 2;  public int[] b = new int[] { 1, 2 };//←取得できない } Object obj = new TestClass(); Type type = obj.GetType(); foreach (FieldInfo fi in type.GetFields()) {  object tmp = fi.GetValue(obj);  Console.WriteLine(fi.Name + ":" + tmp); } System.Console.ReadLine();

  • Stringの値で型キャストしたい(Java)

    最近OKWaveでお世話になっています。 表現がおかしいかもしれませんが、Stringの変数の値を使って、型キャストしたいです。 様々なオブジェクトが入る配列(Vector)を使用しているため、VectorをObject型にして使用しています。 配列のある要素をget()したのち、getClass().getSimpleName()でクラス名を取得し、そのクラス名を、 Object obj = array.get(i); String name = obj.getClass().getSimpleName(); if(name.equal("Integer")) {  method((Integer)obj);   ・   ・   ・ のような形で、場合分けして、メソッドを呼び出しています。 ですが、この方法だと、条件分岐が増えて、見づらいです。 そこで、クラス名を取得したnameをうまく使ってobjを型キャストしたいです。 これを解決させる方法もしくはヒントを教えてください!

    • ベストアンサー
    • Java
  • C# Wordファイルから文章データを取得

    いつもお世話になっております。 只今、Wordの中身をリッチテキストボックスに取得しようとしています。 取得したデータを他の形式に変更するので、中身を編集というのはしない予定です。 取り込むこと自体はできるようになりまして なんとかなるかなと思っていたのですが、動作を確認していると どうも大きなファイルだと上手くいかないのです。 十数ページなら何とかいけても、数十ページだとエラーが出ます。 そこで質問です。  1:考えられる原因にはどんなものがあるでしょうか     クリップボードを利用してるので、そこが怪しいですが     ほかにありましたらお願いします。  2:解決する方法にはどんなものがあるでしょうか?  3:この方法以外にWordのデータを取得する方法はあるでしょうか?   (クリップボードを利用する以外の方法) ソースは以下のように記述しました。 --------------------------------- Type wt = Type.GetTypeFromProgID("Word.Application"); Object wApp = Activator.CreateInstance(wt); try {     Object tmpDoc = wApp.GetType().InvokeMember("Documents", BindingFlags.GetProperty, null, wApp, null);     object[] tmpFile = {             fileName,             false,             true,             false,             Type.Missing,             Type.Missing,             true,             Type.Missing,             Type.Missing,             Type.Missing,             Type.Missing,             false,             true,             Type.Missing,             true,             Type.Missing            };     Object wDoc = tmpDoc.GetType().InvokeMember("Open", BindingFlags.InvokeMethod, null, tmpDoc, tmpFile);     Object activeW = wDoc.GetType().InvokeMember("ActiveWindow", BindingFlags.GetProperty, null, wDoc, null);     Object activeWSelection = activeW.GetType().InvokeMember("Selection", BindingFlags.GetProperty, null, activeW, null);     activeWSelection.GetType().InvokeMember("WholeStory", BindingFlags.InvokeMethod, null, activeWSelection, null);     activeWSelection.GetType().InvokeMember("Copy", BindingFlags.InvokeMethod, null, activeWSelection, null);     //クリップボードの中身取得     IDataObject data = Clipboard.GetDataObject();     //リッチテキストボックス(rTextにデータを挿入)     rText.Rtf = data.GetData(DataFormats.Rtf).ToString(); } catch (Exception ex) {     MessageBox.Show(ex.ToString()); } finally {     Object apApp = wApp.GetType().InvokeMember("Application", BindingFlags.GetProperty, null, wApp, null);     apApp.GetType().InvokeMember("Quit", BindingFlags.InvokeMethod, null, apApp, new object[] { Type.Missing, Type.Missing, Type.Missing }); } --------------------------------- あちこち参考サイトを見て回っているのですが 捜し方が悪いのか、クリップボードを利用する方法以外が見つかりません。 わかる方がいましたら、よろしくお願いします。 開発環境:VisualStudio2008 実行環境:Vista Word:*.doc/*.docx

  • 実行時に確定するメソッドを呼び出す方法について

    invoke()メソッドや、Methodクラスを 使用するなど。以前に小耳にはさんだ。記憶があります。 以下の3つの引数から 動的に該当メソッドを呼び出す。 処理を実装コードがすぐだせる方がいると 助かります。 Object foo(Object obj, String methodName, Collection param) (1)該当オブジェクト getClass()などで、該当クラスを動的に  特定。 (2)、(1)が保有しているメソッドのうち、 発行したいメソッドの名前 (3) parmには1要素ごとに2要素のObject[]型を   を格納して、 Object[0]の要素にかんしてはが引数の型についての完全修飾クラス名をあらわすString型。   Object[1]については実際に入っている値。 上記3つの引数をうけとって内部で getClass()とかつかって 必要な情報はすべて実行時に動的に 取得して objの該当オブジェクトを 発行し、foo()メソッド自体の 返却値はそのメソッドの返却値とする という ロジックの実装のサンプルがあると。 とても、うれしいです。 じゃ、void型が返却の時どうすんねん。 とか、staticの時どうすんねん。 とか、その変のアイデア持ってる 人がいるととてもうれしい。 以上

    • ベストアンサー
    • Java
  • 外部jarの標準出力を取得できますか?

    ClassLoaderで外部jarのクラスをロードし、実行するプログラムを作りました。 SimpleOutputは、単に渡された引数を標準出力に出すだけのものです。 この値を取得してGUI上に表示させたいのですが、取得する方法をご教授ください。 System.out.println("Load class"); URL[] urls = { file.toURI().toURL() }; ClassLoader loader = URLClassLoader.newInstance(urls); Class<?> cls = loader.loadClass("SimpleOutput"); System.out.println(cls); Object obj = cls.newInstance(); Method method = cls.getMethod("main", String[].class); String[] av = {"test"}; method.invoke(obj, new Object[]{av});

    • ベストアンサー
    • Java
  • Java リフレクションについて

    1.リフレクションを使い、値をセット(BeanのSetterメソッドにて) 2.1でセットした値を取得するために、下記コードで取得 Method Method = Class.getMethod("getLstData"); Object obj = Method.invoke(****); 上記の****の箇所には、メソッドのあるクラスのインスタンスを渡す、 というところまでは分かりますが、newInstance()してしまうと、新しいオブジェクトになってしまうので 値が取得できません。 error>>java.lang.IllegalArgumentException: object is not an instance of declaring class どのようにすれば、値の取得が可能でしょうか。 どなたかご教授いただければと思います。 ※Java 1.5を使用

    • ベストアンサー
    • Java
  • VB6のコードをC#にしたい

    C#はこちらでよかったでしょうか。。カテゴリ違いだったらすみません。 現在、VB6にて書かれているコードを、C#にて置き換える事になりました。 しかし私はまともなオブジェクト指向の言語で組むのも初めてなら、C系の言語で組むのも初めてで、そこでどうすればいいのか困っています。 VB6で sub aa(i as integer)      dim obj as object   call bb(obj,i)   call obj.run()    end sub    sub bb(byref pobj as object,i as integer)      select case i    case 1:     pobj = new obj1    case 2:     pobj = new obj2   end select    end sub    といったようなコードがあります。obj1とobj2はVBのクラスなのですが、メソッドはどちらも同じrunというものが用意されているとします。 ようは引数の値によって、メソッドやプロパティの形は同じだけれど、メソッドの中身が違うクラスをもらって、そのもらったクラスのメソッドを実行したいわけです。 しかしC#でまったく等価のソースをかくと、当然ながらobjはただのobject形なので、そんなメソッドはないとおこられてしまいます。VB6の場合、そのあたりが厳密でないので許されていたのですが。。。 こういった場合、どのようにソースをかけばいいのでしょうか? やはりobj1,obj2のクラスの方に工夫しないといけないでしょうか? 実はこのオブジェクトを用意しているのが別チームの為、その場合こうしてくれと提案しなくてはなりません。もしそれがなくても可能であればそれにこした事はないのですが。。。 いちおうもらったクラスのタイプをしらべて、それごとにコードをかくという方法は思いついたのですが、それだとobj1、obj2にあたるクラス数が実は種類がたくさんあり、そこだけならまだしも、他にも同じようなコードをたくさんかかなくてはいけなくなってしまいます。 もう少しスマートにするにはどのようにすればいいでしょうか? こういうクラス構成にすれば、とか教えていただければ助かります。

  • リフレクション

    リフレクションによって、Stringの値(strVal)を各クラスのオブジェクトに変換したいと思っております。 下のようなコードで、this.typeにセットしてあるオブジェクトのvalueOfメソッドを実行したいのですが、clazz.getMethod部分で次のようなExceptionが発生してしまいます。 staticメソッドはgetMethodでは取得・実行できないのでしょうか? ご存知の方いらっしゃいましたら、教えて頂けないでしょうか。 【Exception】 java.lang.NoSuchMethodException: java.lang.String.valueOf() 【コード】 Class clazz = Class.forName(this.type); Method method = clazz.getMethod("valueOf", new Class[0]); return method.invoke(clazz.newInstance(), new Object[]{strVal} ); 今回、this.typeには、"java.lang.String"が入っています。

    • ベストアンサー
    • Java
  • InvokeMemberメソッドとは何をするメソッドでしょうか?

    はじめまして、質問です。 C#のソースコードで、「Type.InvokeMember メソッド」というのを使っている箇所があるのですが、 これがいったい何をするメソッドなのかよく分かりません。 msdnのヘルプでは、 「指定したバインディング制約を使用し、指定した引数リストと照合して、指定したメンバを呼び出します。 」 と言っていますが、知識不足で理解できていません。 ネットで検索しても参考になりそうなものが引っかからない状況です。 実際に使用している箇所のソースコードは以下のような感じです。 private void axWebBrowser1_NavigateComplete2(object sender, AxSHDocVw.DWebBrowserEvents2_NavigateComplete2Event e) { Object o = e.pDisp; Object oDocument = null; oDocument = o.GetType().InvokeMember("Document",BindingFlags.GetProperty,null,o,null); o.GetType().InvokeMember("Application",BindingFlags.GetProperty,null,oDocument,null); 中略 } ご存知の方がいらっしゃいましたら宜しくお願い致します。 何か参考になるURLや、このように調べるべきだなどのアドバイスなどもありましたら、 ぜひお願い致します。

専門家に質問してみよう