有没有办法让这段代码更短?

5
//list the controls from the  main form
foreach (Control c in Controls)
{
    if (c is ComboBox)
    {
        ((ComboBox)c).SelectedIndex = -1;
    }
    else if (c is TextBox)
    {
        ((TextBox)c).Text = "";
    }
    else if (c is CheckBox)
    {
        ((CheckBox)c).Checked = false;
    }
    //etc. with FIFTY different types to check against
}

在 C# 7 中(正在开发中),它可以肯定地解决这样的问题...但对于今天的版本来说,情况并非如此。 - Ahmed ilyas
1
这里的目标是什么? - USER_8675309
2
@fre3land,你有50种控件类型,还是这三种类型的50个控件?如果你有50种不同的类型,那么是的,你确实需要更好的模式;如果你有这三种类型的50个控件,那么你现有的代码应该足够了。 - Servy
50种控件,先生。 - fre3land
你也可以删除 if 语句中的 { } 和换行符。 - H. Pauwelyn
显示剩余3条评论
3个回答

9

一种方法是为特定类型添加三个重载的方法,将其转换为dynamic,并进行如下调用:

foreach (dynamic c in Controls) {
    ClearOut(c);
}
...
private static void ClearOut(ComboBox c) {
    c.SelectedIndex = -1;
}
private static void ClearOut(TextBox t) {
    t.Text = string.Empty;
}
private static void ClearOut(CheckBox c) {
    c.Checked = false;
}

由于cdynamic的,C#会将ClearOut方法的绑定推迟到运行时,从而使代码看起来更加清晰。这种方法的缺点是,在编译时,C#无法告诉您是否缺少其中一个重载。


真的很好。我不知道这个。但是50个方法不会很短。 - M.kazem Akhgary
2
如果您将“Control”用作“c”的类型,C# 将尝试在编译时进行方法绑定,并失败,因为没有重载接受“Control”的“ClearOut”。 - Sergey Kalinichenko
2
“50种方法不会太少”是真的,但有时候这已经是最好的了。而且,逐个处理每个项目比每次都要检查50次要更好。 - Casey ScriptFu Pharr
1
@M.kazemAkhgary 这是因为你在列表上有一个没有对应方法的控件,对吧?你可以通过添加一个接受Control参数的重载方法,并设置断点来捕获这种情况。 - Sergey Kalinichenko
1
你很聪明。是啊,我忘了我有按钮控件了。现在它运行得很好。 - M.kazem Akhgary
显示剩余4条评论

6
使用这种方法来设置你的控件属性:
public void Set(object obj, string property, object value)
{
    //use reflection to get the PropertyInfo of the property you want to set
    //if the property is not found, GetProperty() returns null
    var propertyInfo = obj.GetType().GetProperty(property);
    //use the C# 6 ?. operator to only execute SetValue() if propertyInfo is not null
    propertyInfo?.SetValue(obj, value);
}

这样调用:

foreach (Control c in Controls)
{
    Set(c, "SelectedIndex", -1);
    Set(c, "Text", "");
    Set(c, "Checked", false);
}

1
这很有帮助,非常感谢。 - fre3land
2
这不会在每次迭代中运行所有50个检查吗? - AlG
@AIG - 确实,这是一个性能问题。我还需要指出,这适用于C# 6+。 - Ahmed ilyas
为什么代码在C# VS 14上不能工作? - fre3land
1
为什么不将所有内容存储在数据结构中,然后一旦找到匹配项就退出for循环并运行呢? - Emil
显示剩余5条评论

3

您可以创建一个从每个支持的类型到清除该类型控件的操作的查找表,然后为每个支持的类型添加处理程序:

public class ControlClearer
{
    private static Dictionary<Type, Action<Control>> lookup = new Dictionary<Type, Action<Control>>();

    static ControlClearer()
    {
        AddMapping((TextBox control) => control.Text = "");
        AddMapping((ComboBox control) => control.SelectedIndex = -1);
        AddMapping((CheckBox control) => control.Checked = false);
    }

    private static void AddMapping<T>(Action<T> clearAction)
        where T : Control
    {
        lookup[typeof(T)] = control => clearAction((T)(object)control);
    }

    public static void Clear<T>(T control)
        where T : Control
    {
        //todo support case where T isn't in the dictionary
        lookup[typeof(T)](control);
    }

    public static void Clear(Control control)
    {
        //todo support case where the type isn't in the dictionary
        lookup[control.GetType()](control);
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接