限制基类参数的类型

时间:2012-02-08 01:50:19

标签: c# winforms .net-4.0

我有这样的代码:

public static void ToUpperCase(params Control[] controls)
{
    foreach (Control oControl in controls)
    {
        if (oControl is TextBox)
        {
            oControl.TextChanged += (sndr, evnt) =>
            {
                TextBox txtControl = sndr as TextBox;
                int pos = txtControl.SelectionStart;
                txtControl.Text = txtControl.Text.ToUpper();
                txtControl.SelectionStart = pos;
            };
        }
        else if (oControl is ComboBox)
        {
            oControl.TextChanged += (sndr, evnt) =>
            {
                ComboBox cmbControl = sndr as ComboBox;
                int pos = cmbControl.SelectionStart;
                cmbControl.Text = cmbControl.Text.ToUpper();
                cmbControl.SelectionStart = pos;
            };
        }
        else throw new NotImplementedException(oControl.GetType().DeclaringType.ToString() + " is not allowed.");
    }
}

我希望将params Control[] controls限制为仅接受TextBoxComboBox类型。

我的代码在C#,框架4中,在VS2010Pro中构建,项目在WinForms中。

请帮忙。提前谢谢。

3 个答案:

答案 0 :(得分:5)

你不能 - 他们没有一个好的共同祖先。

你可以(也可能应该)做的是对你的方法进行两次重载,它们采用每种方法的参数:

public static void ToUpperCase(params TextBox[] controls)
{
    foreach (TextBox oControl in controls)
        oControl.TextChanged += (sndr, evnt) =>
        {
            TextBox txtControl = sndr as TextBox ;
            int pos = txtControl.SelectionStart;
            txtControl.Text = txtControl.Text.ToUpper();
            txtControl.SelectionStart = pos;
        };
}

public static void ToUpperCase(params ComboBox[] controls)
{
    foreach (ComboBoxControl oControl in controls)
        oControl.TextChanged += (sndr, evnt) =>
        {
            ComboBox txtControl = sndr as ComboBox;
            int pos = txtControl.SelectionStart;
            txtControl.Text = txtControl.Text.ToUpper();
            txtControl.SelectionStart = pos;
        };
}

答案 1 :(得分:4)

通常,您应该为TextBox或ComboBox使用公共基类,但这已经是Control。此外,您无法更改这些基类。

我能想到的最好的方法是添加一个Debug.Assert来检查类型。 类似的东西:

foreach (var control in controls)
    Debug.Assert((control is TextBox) || (control is ComboBox));

答案 2 :(得分:4)

选项一

如果您希望能够在函数中传递混合的文本框和组合框并仍然进行静态类型检查,那么您可以通过以下方式实现它。

public interface ISupportUpperCase {
    event EventHandler ValueChanged;
    void TransformValueToUpperCase();
}

public class UpperCaseableTextbox : Textbox, ISupportUpperCase {
  //TextChanged event is already here, just use it.

  //Implement TransformValueToUpperCase in a way that suits your control
  public void TransformValueToUpperCase() {
     int pos = this.SelectionStart;
     this.Text = this.Text.ToUpper();
     this.SelectionStart = pos;
  }
}

public class UpperCaseableComboBox : ComboBox, ISupportUpperCase {
  //TextChanged event is already here, just use it.
  //Implement TransformValueToUpperCase in a way that suits your control
}

然后你的功能将是:

public static void ToUpperCase(params ISupportUpperCase[] controls)
{
    foreach (var oControl in controls)
    {
        oControl.TextChanged += (sndr, evnt) =>
        {
            oControl.TransformValueToUpperCase();
        }
    }
}

通过这样做,你最终得到了更好的封装,因为只有特定的控件应该知道如何使ITS值为UpperCase,而不是某些魔术函数。 您还可以轻松地引入更多支持此功能的控件,而无需更改其他功能。

选项二

事实上,你可以用同样的方法完全摆脱这个功能,只需稍微改变界面:

public interface ISupportUpperCase {
    bool AlwaysInUpperCase { get; set }
}

所以你的控件将根据这个标志对这个功能负全部责任:

public class UpperCaseableTextbox : Textbox, ISupportUpperCase {

  public bool AlwaysInUpperCase { get; set }

  //constructor
  public UpperCaseableTextbox () {
     this.TextChanged += (sender, args) => {
        if (this.AlwaysInUpperCase) {
           int pos = this.SelectionStart;
           this.Text = this.Text.ToUpper();
           this.SelectionStart = pos;
        }
     }
  }
}

因此,当您需要控件始终为大写并且控件将自行管理时,您可以设置属性,而不是使用函数。