- - PR -
引数であるobject型を復元する方法(C#)
1|2|3
次のページへ»
投稿者 | 投稿内容 | ||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
投稿日時: 2004-03-20 01:15
メソッドの引数であるobjectを復元して適切な処理を選択したいです。
より洗練された実装方法はありますか? (添付ロジックを参照願います) <不満に思う点> ロジックが正常に機能するかどうかは、AddMain()のGetType().nameの判定が 正しいことを前提にしています。これではバグが入り込む危険性があります。 ただし、引数の柔軟性は確保したいのでobjectによる引渡しを放棄して メソッドをoverrideする手法は採用したくありません。 質問 AddMain()にバグが入り込み難い実装方法はあるでしょうか? GetType()およびTypeクラス を想定しての質問ですが、 優れたアイデアであれば特定の手法に固執はしません。 /// <summary> /// リフレクション実行例 /// </summary> public class Class1 { // Form1.csの記述 // Class1 cs1 = new Class1(); // string str = cs1.Example(); // textBox1.Text = str; // textBox1.Update(); // Example() 実行結果 // 123+456 // 579 public class csStr { private string x; private string y; internal csStr(string px,string py) { this.x = px; this.y = py; } internal string Add() { return this.x+"+"+this.y; } } public class csInt { private int x; private int y; internal csInt(int px,int py) { this.x = px; this.y = py; } internal string Add() { int temp = this.x+this.y; return temp.ToString(); } } public string Example() { const string NewLine = "\\r\\n"; csStr cs1 = new csStr("123","456"); csInt cs2 = new csInt(123,456); return MainAdd(cs1)+NewLine+MainAdd(cs2)+NewLine; } private string MainAdd(object obj) { string ans =""; string temp = obj.GetType().Name; switch(temp) { case "csStr": { // (csStr)の整合性をコンパイル時にチェックできない csStr cs = (csStr)obj; ans = cs.Add(); } break; case "csInt": { // (csInt)の整合性をコンパイル時にチェックできない csInt cs = (csInt)obj; ans = cs.Add(); } break; } return ans; } } | ||||||||||||||||||||
|
投稿日時: 2004-03-20 01:36
やりたいことにやや疑問があるのでこんなのでいいのか分かりませんが…
例えばインターフェイスを使って、
とか。 別にMainAdd(AddMain?)は要らないと思いますが、もし定義するとすれば、
--追記 >ただし、引数の柔軟性は確保したいのでobjectによる引渡しを放棄して >メソッドをoverrideする手法は採用したくありません。 てかこういう事がしたくないってことですか…? [ メッセージ編集済み 編集者: なちゃ 編集日時 2004-03-20 01:38 ] | ||||||||||||||||||||
|
投稿日時: 2004-03-20 11:12
もしMainAdd()が「渡された引数のAdd()を呼び出す」という機能ならば、なちゃさんの仰るようにインターフェースを実装するのが良いと思います。
そしてその場合はMainAddは要りません。直接オブジェクトのAdd()を呼んでください。 これがもし、「Intだったらこういう処理をする」「ArrayListだったらこういう処理をする」 という風にライブラリに元々あるオブジェクトも処理するつもりなら、MainAdd()をオーバーロード(多重定義)してください。 これ以降はひろしさんの >メソッドをoverrideする手法は はオーバーロードの間違いだったと勝手に推測して話を進めさせていただきますが、ひろしさんは「オーバーロードすると柔軟性が失われる」というのは、例えばどのような場合を想定されていますか? object型の引数を受け取るメソッドを一つだけ定義し、その中で「Intの時はこうする」「csStrのときはこうする」「csIntのときはこうする」と処理を分けようが、あるいは渡される型の数だけメソッドを(多重)定義しようが、結局想定されていない型のオブジェクトには対応できませんよね。 そして対応するオブジェクトに関しては、「どのように処理するか書かなければいけない」点についても同じです。 例えば、「今度doubleにも対応することになった」と変更になった場合に、いずれの方法をとっていてもdoubleの場合の処理を書かなければ対応できないということです。 「たくさんの種類の型に対応しなければならないのでメソッドがそれだけたくさんになってしまう」「後から対応する型を増やすたびにどんどんメソッドが増えていく」というのが嫌なのかもしれませんが、「MessageBox.Show()メソッドはたくさんあってもう訳分かんない」と言っている人をいまだかつて見たことはありません。 ひろしさんの提示されたソースは、説明する為に必要な部分だけを抜き出したものだと思いますので、実際何をするためのものなのか分からないので断定はできませんが、オーバーロードをするのが最も洗練された実装方法だと思います。 余談ですが、C#にはis演算子というものがあります。 GetType().Nameではなくてこちらを使ってみてはいかがでしょうか。 | ||||||||||||||||||||
|
投稿日時: 2004-03-20 12:23
ご返答ありがとうございます。
未だ、interfaceを使っていなかったのでその点でとても参考になりました。 なかなかうまく説明できませんが、補足させていただきます。 MainAdd()でやりたかったこと 「個別の型(例題ではクラス)に関する記述を排除して共通の実行手順を定義する方法は ないだろうか?」 例題では、MainAdd()が受け取る型がcsInt,csStrの2クラスだけでした。 これが10クラスに増えたとします。 そして、各クラスが実装しているメソッドもAdd()だけでなく5種類に増えたとします。 ところで、このメソッドには10種類のクラス共通の実行手順が定義できるとします。 このケースでは共通の実行手順だけを抽出して部品化するのが自然に思えます。 object型によるパラメータ引渡しとGetType()にこだわったのは上記の背景からです。 質問1 object渡しにこだわった場合ですが、 GetType()に多くのメンバーあって使いこなせません。 けれども、GetType().nameによる型の判別では危なっかしく感じます。 確実な判別をするにはどのGetType()メンバーを採用したら良いでしょうか? 質問2 そもそも、型ごとの分岐(switch文)を使いたくないのです。 objetctに格納されている「型」そのものを生成できないのでしょうか? あるいは、object渡しにこだわらずに上記の目的を達成することは可能でしょうか? -追記- わかりにくい説明+ソースコードですみません。 ところで、掲載時にソースコードの空白が消えないようにするには どうすれば良いのでしょうか? | ||||||||||||||||||||
|
投稿日時: 2004-03-20 13:03
一郎さん、ご返答ありがとうございます。
かぶってしまいました。(すみません) 一郎さんが推察された通りのことを私は感じていました。 私が模索している手法には無理があるということですね。 | ||||||||||||||||||||
|
投稿日時: 2004-03-20 13:07
諸農です。
なちゃさんとほぼ同じになりそうなんですが インタフェースを定義しておいて、共通ルーチン(MainAdd?)で インタフェースを抽出して処理すればいいのではないでしょうか。 もちろん。インタフェースを実装していないクラスでは処理は行え ませんので、目的にかなっているのではないかと思います。
codeタグで括ります。 ではでは(^^)/ _________________ 諸農和岳 Powered by Turbo Delphi & Microsoft Visual Studio 2005 十兵衛@わんくま同盟 http://blogs.wankuma.com/jubei/ | ||||||||||||||||||||
|
投稿日時: 2004-03-20 13:09
実現方法は色々あるでしょうけど、ぱっと思いつくのは例えば、テンプレート内に発生する各操作をインターフェイスで定義して、MainAddを共通手順のテンプレートとする。 まあ、最初に書いたインターフェイスを使う方法の応用ですが。
# とりあえず書いただけなので各メソッドの型とかは気にせずに… 見てのとおり、MainAddは共通の操作手順を実装しており、各手順における具体的な動作はパラメータの各クラスで実装します。これで、共通の操作を可能にしたいクラスはIProcedurableを実装するというルールになります。 # IProcedurableを実装するクラスは、共通手順による操作が可能ともいえる 要件によってこんなので済むのか、もっといろいろ考えないといけないのかなどはあるでしょうけど。
型を厳密に判定するには、その型のType同士が同じインスタンスである事を確認すればよいので、 if (obj.GetType() == typeof(TargetType)) … とかでいけます(Typeを元に判別する場合の話)。ただし、これは継承関係とかにあっても違う型と判別されるので、場合によってはIsAsignable(だったかな?)とかIsSubClassOf(だったかな?)とか(インスタンスを実装しているか調べるのもあったかな?)を使います。
通常は、そういう目的のために使えるのが継承またはインターフェイスの実装によって得られるポリモーフィズムの機構です(インターフェイスを使った一例がサンプルのコードに示した物です)。
BBコードのCODEってのを使います。投稿時に下のリンクを開けば載ってます。 --追記 微妙にかぶった… [ メッセージ編集済み 編集者: なちゃ 編集日時 2004-03-20 13:15 ] | ||||||||||||||||||||
|
投稿日時: 2004-03-20 16:18
ご回答ありがとうございました。
interfaceの使ってみようと思います。 |
1|2|3
次のページへ»