代码之家  ›  专栏  ›  技术社区  ›  James Hughes

指定委托参数的特定类型

c#
  •  0
  • James Hughes  · 技术社区  · 17 年前

    假设我有以下代表

    public delegate void ControlInitializer(Control control);
    

    在指定委托时,是否可以指定输入参数是什么类型的控件?例如

    而不是

    ControlInitializer one = c => ((TextBox)c).Text = "Init Value"
    ControlInitializer two = c => ((DropDownList)c).SelectedValue= "-1"
    

    我能做点什么吗

    ControlInitializer one = (TextBox c) => c.Text = "Init Value"
    ControlInitializer two = (DropDownList c) => c.SelectedValue= "-1"
    

    因为在这种情况下,文本框是控件的子类?

    更新:我还需要将这两个ControlInitializer委托存储在

    Dictionary<string, ControlInitializer>
    

    意志指定

    Dictionary<string, ControlInitializer<Control>>
    

    在这种情况下工作,因为我似乎不能让它工作。

    事先谢谢。

    3 回复  |  直到 17 年前
        1
  •  10
  •   dtb    17 年前

    您可以使委托成为通用的:

    public delegate void ControlInitializer<TControl>(TControl control)
        where TControl : Control;
    

    然后这样使用:

    ControlInitializer<TextBox>      one = c => c.Text = "Init Value";
    ControlInitializer<DropDownList> two = c => c.SelectedValue = "-1";
    

    我猜你的目标是这样的:

    var init = new Init();
    
    init.RegisterInitializer<TextBox>(c => c.Text = "Init Value");
    init.RegisterInitializer<DropDownList>(c => c.SelectValue = "-1");
    
    foreach (var c in Controls)
    {
        init.ApplyInitializer(c);
    }
    

    这有点困难,因为 戴维B 的答案。但是,您可以将类型转换隐藏在抽象后面,如下所示:

    public class Init
    {
        private readonly Dictionary<Type, Action<Control>> initializers;
        ...
    
        public void RegisterInitializer<TControl>(Action<TControl> i)
            where T Control : Control
        {
            initializers.Add(typeof(TControl), c => i((TControl)c));
        }
    
        public void ApplyInitializer(Control c)
        {
           initializers[c.GetType()](c);
        }
    }
    
        2
  •  3
  •   Andreas Grech    17 年前

    首先,使用预定义的委托 Action . 关于指定类型,请使用泛型参数:

    Action<TextBox, string> one = (c,v) => c.Text = v;
    

    这个 行动 委托接受最多4个参数,不返回任何内容( void )

        3
  •  2
  •   Amy B    17 年前

    不能将a添加到 ControlInitializer<TextBox> 一本字典 ControlInitializer<Control> 因为第一个类型不是从第二个类型继承的 (即使 TextBox 继承自 Control 所有这些都是关于泛型中缺乏协方差和反方差。

    您可以编写自己的集合,使其按照预期的方式工作。有一种可能性:

    public class CustomStorage
    {
      private Dictionary<string, object> storage = new Dictionary<string, object>();
    
      public void Remember(string key, object value)
      {
        storage[key] = value;
      }
    
      public object Retrieve(string key)
      {
        object x = storage[key];
        return x;
      }
    
      public U Retrieve<U>(string key)
      {
        U u = (U) storage[key];
        return u;
      }
    }
    

    可以这样使用:

    CustomStorage cs = new CustomStorage();
    ControlInitializer<TextBox> one = c => c.Text = "Init Value";
    ControlInitializer<DropDownList> two = c => c.SelectedValue = "-1";
      //drop the items into the collection ...
    cs.remember("TextBox", one);
    cs.remember("DropDownList", two);
      // ... and fetch them back
    one = cs.Retrieve<ControlInitializer<TextBox>>("TextBox");
    two = cs.Retrieve<ControlInitializer<DropDownList>>("DropDownList");