2011-03-14 104 views
6

我有一个将控件作为参数的函数,并根据控件的类型(例如:TextBox,ComboBox,RadioButton等)执行type-具体代码:在C#/ WPF中确定控件类型的最有效方法

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(),切换这种类型的字符串表示),微软的代码分析工具告诉我使用'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)获得一个控制变量,并且我已经对此变量执行”执行某些操作“,具体取决于它类型。

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

无论哪种方式,我必须在某个时间点打开控制的类型,而这个是我的问题的主题(不管我如何处理它,如果我可以这样说的话)。

回答

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.由于所有的处理程序定位逻辑可言这是很容易修改,以处理inhereting类型,例如(我的代码不这样做,但你的代码所做的那样)

+1

+1,我不知道这个东西。我要看看它是否合适。看起来不错! :) – David 2011-03-14 14:53:58

+2

+1:我不喜欢做switch/if-else类型,感觉不对。这更清洁。 – 2011-03-14 14:55:01

+2

+1:泛型RegisterHandler特别整洁。 – Gibsnag 2011-03-14 15:01:04

0

那么,你不需要在第二个套上使用else if

第二个为什么你把所有这一切放到一个方法中?这样会更好,因为当你调用这个函数时,你应该知道它调用这个方法的控件的类型是什么,并且从那里为这个控件类型做DoSomething而不是所有的条件检查。

+0

我有一个通用的方法,我用于所有控件,我真的不想重复每个控件类型的代码,因为该函数的代码的99%是所有类型(维护 - 噩梦)通用的。另外,我不知道控件的类型。它可以是任何事情,我不能预先知道控件的类型是什么(这就是为什么这是一个静态函数,将控件作为参数,而不是控件类中的实例函数) – David 2011-03-14 14:28:22

+0

“我有一种通用方法,我用于所有控制“ - 不,您不需要或不需要知道控件的类型!它不能是一个**通用的**方法,无论如何... – Ben 2011-03-14 14:40:11

+0

啊是的,你说得对,“通用”不是我应该在那里使用的术语(把这个放在事实上,英语不是我的母语;))。无论如何,我希望你明白我的观点。我将在关于这个主题的问题的未来编辑中添加一些信息。 – David 2011-03-14 14:55:44

0

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

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

0

将通用(与控件无关的)功能重构为单独的函数并在控件特定的函数中具有特定于控件的功能会更好。

然后,您可以在适当情况下从控件专用函数调用通用函数。

+0

我编辑了我的问题,试图更好地解释我的观点。我的问题不是有可能有一个泛型函数或使用特定于类型的方法,而是仅仅为字典切换控件的类型 – David 2011-03-14 15:06:53

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声明的可读性,并尽可能地使用它。另外,避免打开“魔术串”。尽可能使用const strings

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

相关问题