GetType()。Nameを使用してイベントハンドラーで送信者オブジェクトをキャストします
-
10-07-2019 - |
質問
RichTextBoxだけでなくTextboxのイベントハンドラーがあります。 コードは同じですが、
ハンドラー#1で行う:
RichTextBox tb = (RichTextBox)sender
それに応じてハンドラー#2で:
TextBox tb = (TextBox)sender
そうすることで、送信コントロールを完全に操作できます。 私が知りたいのは、送信オブジェクトをそのタイプに応じてTextboxまたはRichTextboxにキャストする方法です
sender.GetType().Name
次に、実行時にコントロールを作成して操作します。そうすれば、イベントハンドラー関数が1つだけ必要になります。コードが少なく、エラーが少なく、保守が簡単で、DRYが簡単です:-)
解決
必要なプロパティに応じて、TextBoxとRichTextBoxの両方がそのサブクラスを継承するため、送信者をTextBoxBaseとしてキャストできます。
他のヒント
キャストする必要はありません。始めたときと同じように考えていましたが、この「パターン」は間違っており、実際には論理的ではありません。
あなたの最善の策は、次のようなものを使用することです:
if (sender is TextBox)
{
TextBox tb = (TextBox)sender;
}
else if (sender is RichTextBox)
{
RichTextBox rtb = (RichTextBox)sender;
}
else
{
// etc
}
これは非常に古い投稿であることは知っていますが、Framework 4では送信者をコントロールとしてキャストできます:
Control cntrl = (Control)sender;
cntrl.Text = "This is a " + sender.GetType().ToString();
すべての異なるコントロールに共通するコントロール(つまりテキスト)のみを参照できることに注意してください。
RichTextBox textbox = sender as RichTextBox;
if (textbox != null)
{
// do stuff as a rtb
textbox.Text = "I'm a rtb";
return;
}
TextBox textbox = sender as TextBox;
if (textbox != null)
{
// do stuff as a textbox
textbox.Text = "I'm a textbox";
}
キャストはコンパイル時にのみ実行できるため、コンパイル時にキャストしたい型を知る必要があります。したがって、キャスト時にランタイムタイプ(GetType()によって返される)は使用できません。
ポリモーフィズムを探している場合は、リフレクションを介してNameプロパティにアクセスできます。イベントハンドラを再利用できるようにするためだけに、私はそのようには行きません。
厳密な型指定が必要な場合は、2人の送信者の共通の基本クラスまたはインターフェイスが唯一の方法です。
タイプ名ではなく、 'を使用できます。は 'です。
タイプを知りたいだけで、オブジェクト参照が不要な場合:
if (sender is RichTextBox)
{
// ...
}
else if (sender is TextBox)
{
// ...
}
ただし、通常はオブジェクトが必要です。C#7には、インラインで値をテストおよび取得できる優れた構文があります。
if (sender is RichTextBox richTextBox)
{
richTextBox.Text = "I am rich";
}
else if (sender is TextBox textBox)
{
textBox.Text = "I am not rich";
}
インライン一時変数を使用してキャストを処理することもできます。
if (sender is RichTextBox tb)
{
// ... //
}
else if (sender is TextBox tb)
{
// ... //
}
コードが同一の場合、注意する必要がありますか? Control
にキャストしても必要なものがすべて得られないのではないかと思います...
1つの複雑なハンドラーが、いくつかの単純なハンドラーよりも優れているとは限りません。いずれにせよ、このルートに行くために持っている場合、「as」「/」「is」望ましい(文字列などに依存しません):
TextBox tb = sender as TextBox;
if(tb!=null) {/* TextBox specific code */}
...
コードを繰り返したくない場合は、両方のコントロールをキャストし、共通アクションをTextBoxBaseを引数として取る別のメソッドにリファクタリングできます。また、両方のコントロールがTexbBoxBaseから派生し、メソッドを呼び出すため、イベントハンドラーでコントロールをSystem.Windows.Forms.TextBoxBaseに変換します。
これらのコントロールの特定のプロパティが必要な場合、このリファクタリングは機能しません。
上記のコードの汎用バージョン:
public static void CastAndUse<T>(object item, Action<T> action) where T : class
{
T thing = item as T;
if (thing != null)
{
action(thing);
}
}
次の用途:
CastAndUse(sender, new Action((foo) => foo = bar));
完璧ではありませんが、便利です。