在C#/ WPF中确定控件类型的最有效方法

时间:2011-03-14 14:19:49

标签: c# wpf syntax types

我有一个函数将控件作为参数,并且根据控件的类型(例如: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的代码分析工具告诉我使用'as '而不是'是'这样的(因为它在性能方面更好):

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.....
        }
    }
}

但我发现这最后的解决方案相当冗长而且不太实用。 我希望能够直接打开控件的类型,但是由于switch的case语句不能包含变量而无法使用字符串表示(我完全不喜欢),因此无法这样做。

那么,什么才是最好的表现方式呢?在你看来,最好的办法是什么? (不一定是性能方面,但“例如代码可读性”)

编辑关于“我为什么要使用一个常用功能而不是特定类型的方法”的主题正在进行中,这里有更多信息:

我从我正在处理的应用程序的其他部分(type = Control)获取一个控制变量,我根据其类型对此变量做“做某事”。

所以基本上,我可以选择2个选项:要么我使用一个常用函数并检查函数体内控件的类型,以便在某个时刻执行代码的正确部分(我现在选择的选项,但这可能会改变),或者我在调用类型特定的方法之前检查控件的类型。

无论哪种方式,我都必须在某个时刻打开控件的类型,这个是我的问题的主题(不管我用它做什么,如果我可以这么说的话)。< / p>

5 个答案:

答案 0 :(得分:8)

我会使用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.由于所有处理程序定位逻辑都没有重复,因此很容易修改它以便处理固有类型(例如我的代码不会执行此操作)

答案 1 :(得分:0)

好吧,你不需要在第二个上使用else if嵌套。

其次,为什么要将所有这些都放在一个方法中?它会更好,因为在你调用它时你应该知道它调用这个方法的控件的类型是什么,并从那里只执行该控件类型的DoSomething而不是所有这些条件检查。

答案 2 :(得分:0)

我认为你在这里使用“is”运算符很好。它更具可读性,并且在控件不是的情况下,您实际上没有任何有用的备用路径。在这种情况下,我不认为时间差异是至关重要的。

你可以通过从每个单独的if块返回来替换一系列简单的“if”的“else if”,但这是个人风格的选择。

答案 3 :(得分:0)

最好将通用(控件不可知)功能重构为单独的函数,并在控件特定的函数中具有特定于控件的功能。

然后,您可以在适当的时候从特定于控件的函数中调用泛型函数。

答案 4 :(得分:0)

这是我选择的解决方案:

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语句的可读性,并尽可能尝试使用它。另外,避免打开“Magic Strings”。尽可能使用const strings

如果你不介意我问,那你究竟想做什么?可能有一个更好的解决方案,不需要推断控件的类型。