наиболее эффективный способ определения типа элемента управления в C # / WPF - PullRequest
6 голосов
/ 14 марта 2011

У меня есть функция, которая принимает элемент управления в качестве параметра и, в зависимости от типа элемента управления (например, TextBox, ComboBox, RadioButton и т. Д.), Выполняет код, зависящий от типа:

internal static void DoSomething(Control control)
{
    if (control is Button)
    {
        // code for button
    }

    else if (control is CheckBox)
    {
        // code for CheckBox
    }

    else if (control is TextBox)
    {
        // code for TextBox
    }

    // etc.....
}

Мне интересно, если это лучший способ сделать.

Я знаю несколько других способов сделать то же самое (например: поиск типа элемента управления с помощью GetType(), включение строкового представления этого типа), и инструмент анализа кода Microsoft говорит мне использовать «как» вместо «как», как это (потому что это лучше с точки зрения производительности):

internal static void DoSomething(Control control)
{
    Button button = control as Button
    if (button != null)
    {
        // code for button
    }

    else
    {
        CheckBox checkBox = control as CheckBox;
        if (checkBox != null)
        {
            // code for CheckBox
        }

        else
        {
            TextBox textBox = control as TextBox;
            if (textBox != null)
            {
                // code for TextBox
            }

            // etc.....
        }
    }
}

, но я считаю, что это последнее решение довольно многословно, а неочень практично читать.Я хотел бы иметь возможность напрямую включать тип элемента управления, но не могу этого сделать, не прибегая к использованию строкового представления (что мне совсем не нравится), поскольку оператор case переключателя не может содержать переменную.

Так что же на самом деле является лучшим способом повышения производительности?и какой, по вашему мнению, лучший способ сделать?(не обязательно с точки зрения производительности, но с точки зрения «читаемости кода»)

Редактировать: так как много происходит по вопросу «почему я использую одну общую функциюи не так много специфичных для типа методов ", вот еще некоторая информация:

Я получаю управляющую переменную из другой части приложения, над которым я работаю (type = Control), и я делаю" сделать что-то ""с этой переменной, в зависимости от ее типа.

так что в основном у меня есть выбор между 2 вариантами: либо я использую одну общую функцию и проверяю тип элемента управления в теле функции, чтобы выполнить правильную частькод в какой-то момент (параметры, которые я выбрал на данный момент, но это может измениться), или я проверяю тип элемента управления ДО вызова метода конкретного типа.

в любом случае, я должен включить элемент управлениявведите в какой-то момент, и ЭТО является предметом моего вопроса (независимо от того, что я с ним делаю, если можно так сказать).

Ответы [ 5 ]

8 голосов
/ 14 марта 2011

Я бы использовал Dictionary для него и (также отдельные методы для каждого обработчика):

private static readonly Dictionary<Type, Action<Control>> _handlers
           = new Dictionary<Type, Action<Control>>();


// Handle.. methods
private static void HandleButton(Button button) { ... }
private static void HandleListbox(Listbox listbox) { ... }

private static void RegisterHandler<T>(Action<T> handler)
      where T: Control
{
    _handlers.Add(typeof(T), o => handler((T)o));
}

// invoke this method in static constructor
private static void InitializeHandlers()
{
    RegisterHandler<Button>(HandleButton);
    RegisterHandler<Listbox>(HandleListbox);
}

// finally usage:
internal static void DoSomething(Control control)
{
    var handler = _handlers[control.GetType()];
    handler(control);
}

Преимущество этого подхода заключается в некотором улучшении удобства обслуживания:
1. Вы будете знать, что выВы не зарегистрировали несколько обработчиков для одного и того же типа параметра (словарь выдаст исключение)
2. У вас будут все регистрации обработчиков отдельно, что позволит вам легко определить, какой метод обрабатывает конкретный тип параметра.
3. Так каквся логика определения местоположения обработчика вообще не повторяется, ее довольно легко изменить, например, для обработки наследующих типов (мой код этого не делает, а ваш код)

0 голосов
/ 14 марта 2011

Я бы выбрал такое решение:

internal class MyClass
{
    private const string ButtonTypeAsString = "Button";
    private const string CheckBoxTypeAsString = "CheckBox";
    private const string TextBoxTypeAsString = "TextBox";

    private static string GetTypeAsString(Control control)
    {
        string result = String.empty;

        if (result.Length == 0 && (control as Button) != null)
        {
            result = MyClass.ButtonTypeAsString;
        }

        if (result.Length == 0 && (control as CheckBox) != null)
        {
            result = MyClass.CheckBoxTypeAsString;
        }

        if (result.Length == 0 && (control as TextBox) != null)
        {
            result = MyClass.TextBoxTypeAsString;
        }

        if (result.Length == 0)
        {
            throw new InvalidOperationException("Control type is not handled by this method.");
        }

        return result;
    }

    internal static void DoSomething(Control control)
    {
        string controlTypeAsString = MyClass.GetTypeAsString(control);

        switch (controlTypeAsString)
        {
            case MyClass.ButtonTypeAsString:
                // Button stuff
                break;

            case MyClass.CheckBoxTypeAsString:
                // Checkbox stuff
                break;

            case MyClass.TextBoxTypeAsString:
                // TextBox stuff
                break;

            default:
                throw new InvalidOperationException("Unexpected Control type");
        }
    }
}

... но я уверен, что некоторые найдут это излишним. Лично мне нравится удобочитаемость оператора switch, и я стараюсь использовать его всегда, когда это возможно. Кроме того, избегая включения «Волшебные струны». Используйте const strings, когда это возможно.

Если вы не возражаете, я спрашиваю, что именно вы пытаетесь сделать? Может быть лучшее решение, которое не предполагает вывод типа Control.

0 голосов
/ 14 марта 2011

Я думаю, что вы в порядке, используя оператор "is" здесь.Он более читабелен, и у вас нет действительно полезного альтернативного пути в случае, если элемент управления не является тем, что вы искали в любом случае.Я не верю, что временные различия будут столь критичными в этом случае.

Вы можете поменять местами "else if" для серии простых "if", вернувшись от каждого отдельного блока if, ноэто личный выбор стиля.

0 голосов
/ 14 марта 2011

Было бы лучше преобразовать универсальную (независимую от управления) функциональность в отдельную функцию и иметь функцию, специфичную для управления, в функциях, специфичных для управления.

Затем вы можете вызвать универсальную функцию из функции управления, где это необходимо.

0 голосов
/ 14 марта 2011

Ну, вам не нужно вложить во второе использование else if.

Во-вторых, почему вы все это объединяете в один метод?Было бы лучше, поскольку в момент, когда вы вызываете это, вы должны знать, каков тип элемента управления, который вызывает этот метод, и оттуда просто делать DoSomething для этого типа элемента управления вместо всей этой условной проверки.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...