- PR -

特定のメソッドの等の呼び出しを強制させる方法

投稿者投稿内容
お だ
会議室デビュー日: 2008/04/02
投稿数: 14
投稿日時: 2008-08-06 23:23
コンパイルエラーではないですが、
コード解析で検証するのはどうでしょう?
コンパイル時にかならずコード解析を行う運用にすれば、
引用:

Forteさんの書き込み (2008-08-01 18:29) より:
上記のコードでは、子クラスのコンストラクタで親クラスのNewを強制されます。

同じような要領で、
「コンストラクタ内で」「○○を呼び出さないと」コンパイルエラー
「(IDisposableを継承させて)Dispose内で」「○○を呼び出さないと」コンパイルエラー
といった、メソッドの呼び出しを強制させる方法は無いでしょうか?


引用文に近い事は可能だと思います。
FxCop という解析ツールは Visual Studio でビルドする際に
実行可能でビルドエラーにする事も可能だったと思います。
ただ、解析ツールの習得や解析にかかるコスト等も考慮する必要はあると思います。
unibon
ぬし
会議室デビュー日: 2002/08/22
投稿数: 1532
お住まい・勤務地: 美人谷        良回答(20pt)
投稿日時: 2008-08-07 02:00
引用:

くまっちさんの書き込み (2008-08-06 16:47) より:
よこけんさんが言ってるように
せめてテンプレートメソッドパターンを適用したコードの方が良いでしょう。
*unibonさんのコードを一部修正


ちょっと変な言い訳をしますと、先日書いたコードでは、とくにテンプレートメソッドを使うことを意識しておらず、こうしたらここまではできるんだけど、というところで止まったコードでした。それがたまたまテンプレートメソッドもどきのコードになってしまっていました。
でも、結果としてはテンプレートメソッドもどきであったことに間違いはないです。
unibon
ぬし
会議室デビュー日: 2002/08/22
投稿数: 1532
お住まい・勤務地: 美人谷        良回答(20pt)
投稿日時: 2008-08-07 02:22
引用:

Forteさんの書き込み (2008-08-01 18:29) より:
都合により、自クラスのコンストラクタ内では実行出来ないが、
使用する際は必ず呼んでおいて欲しい処理があるとき、
呼び出しを忘れないようにさせたい事が目的です。


コンパイル時にエラーにできなくても、実行時にエラーにできればよいのならば、いわゆる「初期化フラグ」のようなものを1個持っておくだけで実現できる簡単なことなのですよね。しかし、そうではなくて、コンパイル時にはじけるようにしたいわけですよね。

子クラス(提示されたコードでの SubClass であり、私が書いたコードで言いますと Foo1 です。名前を合わせれば良かったですね。)をコーディングしているときの、コーディングミスを防ぎたいという目的ですと、Foo1 の中で Hoge が呼べてしまうことは防げません。Hoge が呼べてしまうコーディングミスと、強制したいメソッド呼び出しを呼び出すことを忘れてしまうコーディングミスは、強さ(?)的には同じ類のミスだと思いますので、結局ダメだと私は思っています。したがって、テンプレートメソッドも、目的を果たせないと私は考えます。

コンストラクターで実行できない理由として考えられるのは、コンストラクターの引数では与えられず、後からメソッド呼び出しの引数(やプロパティーの set)で与えられるものだからなのでしょうか。だとしたら、コンストラクターの引数で与えるように直すほうがもしかしたら自然なのかもしれません。

また、もしもネイティブリソースに絡むような初期化のたぐいでしたら、あまり言語レベルで解決しようとはこだわらないほうがもしかしたらよいかもしれません。あくまでも、処理系の都合でそうならざるを得ないのですから。

ほかに思ったことですが、やろうとしていることは、子クラスが親クラスを継承することで、子クラスの側で「改造」しようということでしょうか?クラスの「改造」はある程度無理が付きまとうものですので、やはりスマートな解はないかなとも思います。

#以下、追記。

でも、目的を達成するかどうかは別にしても、テンプレートメソッドにはしておくほうが良いでしょう。

[ メッセージ編集済み 編集者: unibon 編集日時 2008-08-07 02:23 ]
unibon
ぬし
会議室デビュー日: 2002/08/22
投稿数: 1532
お住まい・勤務地: 美人谷        良回答(20pt)
投稿日時: 2008-08-07 02:58
引用:

Forteさんの書き込み (2008-08-01 18:29) より:
同じような要領で、
「コンストラクタ内で」「○○を呼び出さないと」コンパイルエラー
「(IDisposableを継承させて)Dispose内で」「○○を呼び出さないと」コンパイルエラー
といった、メソッドの呼び出しを強制させる方法は無いでしょうか?


いろいろ考えてみたのですが、継承させることが問題になっているような気がします。
「○○を呼び出さないと」ということは(広い意味での)コントローラークラスがやることにして、それとは別に、「○○」の呼び出しの後に呼ばれるコールバックメソッドを集めたクラスを別に作り、それをコントローラークラスが集約したほうが良いのではないかと考えました。

具体的なコードなどは良くは分かりませんが、要は継承を使うとメソッドの解決は親クラスのメソッドがそのまま使えて一見楽そうに見えるけど、でもややこしさが増してしまうのではないかと考えます。

ただ、「○○」がどんな処理なのか、にもよるかもしれません。
Forte
会議室デビュー日: 2007/07/24
投稿数: 19
投稿日時: 2008-08-09 17:05
ご返信いただいた皆様、詳しい説明をありがとうございます。

こんなにレスが付くとは思っていなくてびっくりしました。
見た瞬間、冷や汗が出ました(汗

返答が遅くなってしまって申し訳ないです。
内容の濃いレスばかりなので、まずはじっくり読ませていただきます。
Forte
会議室デビュー日: 2007/07/24
投稿数: 19
投稿日時: 2008-08-09 17:45
Jittaさん

引用:

なにをしたいのか、よくわからないのですが。。。

デフォルトのコンストラクタをプライベートにして、コンストラクタと必要なメソッドを実行するスタティックなメソッドを用意するとか。

Dispose は、親クラスの Dispose メソッドが必要な処理を行い、回りにさせるべきではないでしょう。



抽象的な話ばかりですみません。
具体的に何をしたかったのかと言うと・・・

コード:

Class Form1
Sub New()
InitializeComponent()
UserButton1.Initialize() ' ←呼び忘れられると困る
End Sub
End Class

''' <summary>
''' ユーザーコントロール
''' </summary>
''' <remarks></remarks>
Class UserButton
Inherits Button

''' <summary>本コントロールの初期化</summary>
''' <remarks>画面が表示される前に呼んでおく必要がある</remarks>
Sub Initialize()
'ファイルを参照して、コントロールの表示言語を切り替える処理
'-─────-───-───-──-──-──-─-─-─-─--─--─--─--─
' ↑ファイルを参照するコードがあるため、例外が発生する可能性がある。
' コンストラクタ内に記述すると、コントロールを貼り付けた際にコードが
' 実行されるため、対象ファイルが存在しないと、デザイナで例外が発生…
'-─────-───-───-──-──-──-─-─-─-─--─--─--─--─
End Sub
End Class



このような関係のオブジェクトがあった時、
ユーザーコントロールを所持するクラスのコンストラクタ内などで、
Initializeメソッドを強制的に呼ばせる方法が無いかなぁ?という事でした。

コード:

<MustCallByCtor> Sub Initialize()
End Sub



のような属性でも付けておいたら、
「俺を使うなら、コレを呼び忘れるなよ!」(コンパイルエラー)
なんて使わせ方が出来ないかなぁ?という事で質問させていただきました。

複数の担当者が編集する可能性があるため、
「これを呼び忘れちゃだめだよ」とコメントに書いておく程度だと、
弱いなぁと思った次第です。

この程度の問題なら、ちょっと注意すれば良いだけの事ですが、
また同じような悩みに当たった時、またコメントに注意書きをするんだと、
なんだかスマートじゃないですよね。

出来るだけForm1側で注意を払わなくても、UserButtonを使用できるような設計が出来るといいんですが・・・


[ メッセージ編集済み 編集者: Forte 編集日時 2008-08-09 18:12 ]
Forte
会議室デビュー日: 2007/07/24
投稿数: 19
投稿日時: 2008-08-09 18:02
unibonさん
とても詳しい内容の返答をありがとうございます。

最初の例に挙げたものが、親クラスと子クラスという関係だったため、
余計に意図を分かりにくくさせてしまっていたかもしれません。

今回の件は、親子関係に無いオブジェクト同士でも、呼び出しを強制させる事が出来ないか、
ということでした。

テンプレートメソッドパターンと似たような設計は、いくつかしたと思います。
こんな名前が付いてるとは知りませんでした。。
たぶん、見直したら怪しいところが一杯あると思います。

時間が出来たらそちらもリファクタリングしてみたいと思います。
Forte
会議室デビュー日: 2007/07/24
投稿数: 19
投稿日時: 2008-08-09 18:20
おださん
返答ありがとうございます。

引用:

コンパイルエラーではないですが、
コード解析で検証するのはどうでしょう?



実現したかった事とかなり近いです!!
コード解析、コード分析といったツールがある事を初めて知りました。

コードにちょちょいと書けばOK、といった手軽さは無いようですが、
とても興味があるので、調べてみようと思います。

スキルアップ/キャリアアップ(JOB@IT)