継承について への返答

投稿で使用できる特殊コードの説明。(別タブで開きます。)
本名は入力しないようにしましょう。
投稿した後で削除するときに使うパスワードです。返答があった後は削除できません。
返答する人が目安にします。相手が小学生か社会人かで返答の仕方も変わります。
最初の投稿が質問の場合、質問者が解決時にチェックしてください。(以降も追加書き込み・返信は可能です。)
※「過去ログ」について書くときはその過去ログのURLも書いてください。

以下の返答は逆順(新しい順)に並んでいます。

投稿者 るきお  () 投稿日時 2008/5/2 06:15:00
>フックの手法(?)でメッセージを横取りし処理を割り込ませるような感じになるのですか?  
はい。そうです。まさにフックと同じイメージです。 
 
>基底クラス側の OnKeyPress をコールしているようなのですが、これが常套手段なのですか? 
はい。そうです。 
ただし、あえて基底クラスのメソッドを呼び出さない場合もありますから状況次第です。 
 
呼び出すべきか否かはMSDNライブラリなどで元のメソッドの機能を見て判断してください。 
 
>DLLとして作成できないのですか?  
できます。 
プロジェクトの種類をクラスライブラリにすればビルドするとDLLになります。 
これだと直接実行できないので困るというのであれば、 
Windowsアプリケーション部分とコントロール部分を別プロジェクトにします。 
 
詳細は初級講座第51回をご覧ください。 
http://homepage1.nifty.com/rucio/main/dotnet/shokyu/standard51.htm
投稿者 みどり  () 投稿日時 2008/5/2 05:41:00
>>5 
 
なるほど、オーバライドによって基底クラスのものを横取りしているような感覚(?)なんですね。 
VB6の頃、フックの手法(?)でメッセージを横取りし処理を割り込ませるような感じになるのですか? 
私はフックによる処理は書いたことがないのでよく分かりませんが、確かフックの場合は割り込ませたい処理を行ってから、元々の処理(ハンドラ?)にメッセージを通知していたような覚えがあるのですが、使用方法のサンプルでは割り込ませたい処理を行う前に基底クラス側の OnKeyPress をコールしているようなのですが、これが常套手段なのですか?(開発環境では Overrides Sub OnKeyPress ...を入力した時点で MyBase.OnKeyPress(e) を補ってくれるので...) 
 
今、勉強をかねて TextBox を拡張(?継承)して電卓入力方式や整数部桁数制限、小数部桁数制限を持たせたものを作ろうと思っているのですが、中級講座-第2回継承の使用方法でもあるように、ビルドによりVB6のころのユーザーコントロール(OCX)見たいな感じで拡張コントロールがツールボックスに現れますが、(表現が難しいのですが)これはDLLとして作成できないのですか? 
手の込んだコントロール(?)を作成した際、納品物のソース渡しも必要な場合、解析、流用されるのを防がなければならないケースもあるもので...
投稿者 るきお  () 投稿日時 2008/5/1 07:24:00
>と、OnKeyPress をコールしていますが、この Mybase は基本クラスで基本クラスの OnKeyPress を呼び出しているのですか?  
>では、このオーバーライドされた OnKeyPress を呼び出すのは?  
面白いご指摘ですと思いました。 
 
標準的な処理の流れは次のようになっています。 
トリガー→TextBox.OnKeyPress→TextBoxのKeyPressイベント 
(「トリガー」はもともとOnKeyPressをコールしていたものです。 
OnKeyPressは.NET Frameworkからコールされます。 
興味があれば呼び出し履歴をさかのぼってみてください) 
 
ここでOnKeyPressを上書きすると流れは次のようになります。 
トリガー→TextBoxEx.OnKeyPress 
 
さらにTextBoxEx.OnKeyPressがTextBox.OnKeyPressを呼び出すので、こうなります。 
トリガー→TextBoxEx.OnKeyPress→TextBox.OnKeyPress→TextBoxのKeyPressイベント 
 
これでOnKeyPressを上書きしてもちゃんとイベントが発生するようになります。 
ただ、これだけだと上書きする意味がないのでOnKeyPressに独自の処理を追加します。 
そうすると、こうなります。 
トリガー→TextBoxEx.OnKeyPress 
→①TextBox.OnKeyPress→TextBoxのKeyPressイベント 
→②独自の処理 
 
ちょっと表現しにくいのですが、①と②は処理の順番です。どちらもTextBoxEx.OnKeyPressから呼ばれます。 
 
ですから質問の答えは、 
>基本クラスの OnKeyPress を呼び出しているのですか? 
はい、そうです。 
 
>では、このオーバーライドされた OnKeyPress を呼び出すのは?  
もともと、OnKeyPressを読んでいたものです。上記でトリガーと表現しているものです。 
または、自分でOnKeyPressを呼び出すプログラムを書いた場合には、そのプログラムからも呼ばれます。
投稿者 るきお  () 投稿日時 2008/5/1 07:24:00
>処理の発生順序が変わってくるのではないでしょうか?  
これはOnKeyPressに書いたコードとKeyPressイベントに書いたコード、 
それから、クライアント側でハンドルしたKeyPressイベントのに書いたコードの実行順序の 
ことですよね。 
たしかに無計画に書いていくとつじつまが合わなくなってしまうかもしれませんから要注意ですね。 
 
>将来的な混乱を避けるために  
>手法は統一させた方がいいと思います。  
ライブラリやコントロールの作成者はそれが普通に呼び出されて使用されることだけでなく、 
将来、継承されたりして拡張されることを視野に入れなければいけません。 
ですので、おっしゃるように一般的な方法に統一するのが私もいいと思います。 
でも、そのプロジェクト限定で短納期でなんとかするという使命の場合はまぁ…そこまで 
考えなくてもいいかと思いますけど、この辺のバランス感覚を誤ると大変なことになるときがあります。 
 
>もちろん行き当たりばったりで書いているつもりはないのですが、 
>いろいろな手法が取れる場合、どれが正解って一概に言えないのが困ったものです。 
そうなんです。私も困っています。 
こういうことの積み重ねがスキルなんでしょうか? 
パターンプラクティス集みたいなものがあってもいいかもしれませんね。 
デザインパターンにはそれに近いものがありますが視点がマクロ寄りですね。 
 
なので、とりあえず理由がないときはMSDNライブラリや信頼のできる情報源が 
採用している手法を採用するようにして自衛しましょう。
投稿者 みどり  () 投稿日時 2008/5/1 06:51:00
>>2 
 
はじめまして。 
手法を統一させることってとても重要ですよね。 
もちろん行き当たりばったりで書いているつもりはないのですが、いろいろな手法が取れる場合、どれが正解って一概に言えないのが困ったものです。 
今回の場合、るきおさんのご指摘の通り拡張性に欠けるという欠点があるので別の手法にするのが正解(?)だと思うのですが... 
こういった場合の正攻法ってないもんなんですかねぇ?
投稿者 みどり  () 投稿日時 2008/5/1 06:46:00
>>1 
 
ありがとう御座います。 
 
拡張性が劣っているというのは Private では更なる継承ではこの機能自体は動作するが、もしこの機能を無効にしたい場合や他のキーに変えたい場合、Overrides できないので必ず元の機能 (Private で書かれた機能) が働いてしまうということですよね。 
 
プログラムはこの継承にかかわらず、ひとつのことを動作させるのに無限通り(大げさ?)の手法があるのでいつも悩みのタネになっています。(ここが面白いところかもしれないのですが) 
拡張性、メンテナンス性を考慮し徐々に進化していく場合が多いのですが、なれない言語では思わぬ失敗をしてしまうのが怖く未だに業務ではVB6に頼っています。(VB6から.Netではこの継承が足かせになってしまって...)  
 
あと同じく中級講座-第2回継承の使用方法のサンプルに、 
Public Class TextBoxEx 
    Inherits TextBox 
 
    Protected Overrides Sub OnKeyPress(ByVal e As System.Windows.Forms.KeyPressEventArgs) 
 
        'KeyPressイベントを発生させる。 
        MyBase.OnKeyPress(e) 
      : 
      : 
と、OnKeyPress をコールしていますが、この Mybase は基本クラスで基本クラスの OnKeyPress を呼び出しているのですか? 
では、このオーバーライドされた OnKeyPress を呼び出すのは? 
イベントの発生順序について全く理解できていないので、よろしければ教えてください。
投稿者 うたひこ  () 投稿日時 2008/5/1 06:21:00
こんにちは。 
 
>>1 
>他に何か理由が思いつく方いらっしゃいますか? 
 
処理の発生順序が変わってくるのではないでしょうか? 
どちらがいいかの意見は持ちませんが、 
将来的な混乱を避けるために 
手法は統一させた方がいいと思います。
投稿者 るきお  () 投稿日時 2008/5/1 06:15:00
こんにちは。 
 
フォーカスを移動する機能上は問題ないです。 
 
強いて問題点を挙げるとすると拡張性が劣っている点を私は挙げたいです。 
 
拡張性が劣っているというのは、たとえば、将来だれかがTextBoxExをさらに継承して機能を追加または変更しようとしたときに、Protected Overrides Sub OnKeyPressで宣言してあればそれが可能ですが、Private Sub TextBoxEx_KeyPressでは不可能なばかりか、呼びがすこともできません。 
※Protectedは派生クラスから呼び出せるが、Privateは呼び出せない、OverridesまたはOverridableは派生クラスで機能の変更ができるが、それ以外はできない。 
 
他に何か理由が思いつく方いらっしゃいますか?
投稿者 みどり  () 投稿日時 2008/5/1 05:23:00
はじめまして、みどりと申します。 
最近VB6から.NETへの移行を始めたばかりで、勉強に大変役立たせて頂いております。 
 
中級講座-第2回継承の使用方法に継承の例として「Enterキーが押された場合に自動的に次のコントロールにフォーカスが移動する機能」を持つテキストボックスの継承が紹介されていますが、OnKeyPress を オーバーライドしてこの機能を実現されていますが、以下のように記述しても同様のことが行えてしまいます。(幾つか手を抜いてる箇所がありますが)  
この場合何か問題があるのでしょうか? 
 
Public Class TextBoxEx 
 
    Inherits TextBox 
 
    Private Sub TextBoxEx_KeyPress(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) Handles Me.KeyPress 
 
        If e.KeyChar = Chr(Keys.Enter) Then 
 
            Me.TopLevelControl.SelectNextControl(Me, True, True, True, True) 
 
        End If 
 
    End Sub 
 
End Class