Приведение объекта-отправителя в обработчик событий с использованием GetType (). Name
-
10-07-2019 - |
Вопрос
У меня есть обработчик событий для текстового поля, а также для RichTextBox. Код идентичен, но
В обработчике # 1 я делаю:
RichTextBox tb = (RichTextBox)sender
В обработчике # 2 соответственно:
TextBox tb = (TextBox)sender
Таким образом, я могу полностью управлять элементом управления отправкой. Я хочу знать, как я могу привести отправляющий объект к Textbox или RichTextbox в соответствии с его типом, используя
sender.GetType().Name
, а затем создайте элемент управления во время выполнения и работайте с ним. Таким образом, мне нужна только одна функция обработчика событий: меньше кода, меньше ошибок, проще в обслуживании и СУХОЙ: -)
Решение
В зависимости от того, какие свойства вам нужны, вы можете преобразовать отправителя как TextBoxBase, так как и TextBox, и RichTextBox наследуют этот подкласс.
Другие советы
Тебе никогда не придется кастовать. Когда я начинал, я думал так же, этот «шаблон» неверен и не совсем логичен.
Лучше всего использовать что-то вроде:
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 через отражение. Я бы не пошел таким путем, просто чтобы иметь возможность повторно использовать обработчики событий. Р>
Если вы хотите строгую типизацию, единственный базовый класс или интерфейс для двух отправителей - единственный путь.
Вместо имени типа вы можете использовать ' является .
Если вы просто хотите знать тип и вам не нужна ссылка на объект:
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
не даст вам все, что вам нужно ...
Один сложный обработчик не обязательно лучше, чем несколько простых обработчиков. В любом случае, если вы должны пойти по этому пути, «as» будет «" предпочтительнее (не зависит от строк и т. д.):
TextBox tb = sender as TextBox;
if(tb!=null) {/* TextBox specific code */}
...
если вы не хотите повторять код, тогда вы можете привести оба элемента управления, рефакторинг общих действий в отдельный метод, который принимает TextBoxBase в качестве аргумента. А в ваших обработчиках событий преобразуйте элементы управления в System.Windows.Forms.TextBoxBase, так как оба элемента управления получены из TexbBoxBase и вызывают метод.
Обратите внимание: если вам нужны конкретные свойства любого из этих элементов управления, этот рефакторинг не сработает.
Общая версия приведенного выше кода:
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));
Не идеально, но удобно.