我有一个函数将控件作为参数,并且根据控件的类型(例如: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>
答案 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
。
如果你不介意我问,那你究竟想做什么?可能有一个更好的解决方案,不需要推断控件的类型。