【问题标题】:How to add Func<T, string> of constrained Ts to a collection using that constrained type如何使用该受约束类型将受约束 T 的 Func<T, string> 添加到集合中
【发布时间】:2011-06-12 20:24:57
【问题描述】:

我正在尝试创建函数列表,但我很挣扎。这是一个简化的版本:

public class ValueGetter
{
    public List<Func<Control, string>> Operations { get; set; }

    public ValueGetter()
    {
        this.Operations = new List<Func<Control, string>>();
    }

    public void Map<T>(Func<T, string> valueGetter) where T : Control
    {
        this.Operations.Add(valueGetter);
    }        
}

当我尝试将函数添加到集合时出现问题。我本来可以做到这一点,因为 T 是一个控件,但是这不会编译。

有没有办法可以将函数添加到这个集合中?

【问题讨论】:

    标签: c# generics collections casting expression


    【解决方案1】:

    这是不可能的。

    虽然TControl,但并非所有Controls 都是Ts。
    如果您将Func&lt;TextBox, bool&gt; 添加到列表中,然后使用Button 调用它(作为Func&lt;Control, string&gt;)会发生什么?

    您可以使用covarianceFunc&lt;Control, string&gt; 转换为Func&lt;T, string&gt; where T : Control&gt;,因为任何可能的T 也是Control

    【讨论】:

    • 谢谢,我忘记了 Func 可能不适用于其他类型的控件。
    • @Liath:这里真正需要的是约束“其中 Control : T”,即其中 T 是 Control 或任何基本类型的控件。那么它将是类型安全的。不幸的是,C# 不支持这种约束。如果您正在寻找一种可以表达这种约束的语言,请尝试使用 Scala;我认为他们可以做到。
    【解决方案2】:

    你应该将类声明为泛型:

    public class ValueGetter<T> where T : Control
    {
        public List<Func<T, string>> Operations { get; set; }
    
        public ValueGetter()
        {
            this.Operations = new List<Func<T, string>>();
        }
    
        public void Map(Func<T, string> valueGetter)
        {
            this.Operations.Add(valueGetter);
        }        
    }
    

    【讨论】:

      【解决方案3】:

      这是行不通的,因为您最终会在列表中出现Func&lt;Button, string&gt;,但您最终可以使用Label 来调用它。期望ButtonLabel 相关的函数是什么?

      你可以这样做:

      public class ValueGetter<T> where T : Control
      {
          public List<Func<T, string>> Operations { get; set; }
      
          public ValueGetter()
          {
              this.Operations = new List<Func<T, string>>();
          }
      
          public void Map(Func<T, string> valueGetter)
          {
              this.Operations.Add(valueGetter);
          }
      }
      

      换句话说,每个控件类型都有单独的ValueGetters。

      编辑:另一个想法:您可以添加一个仅在类型正确时才允许操作的函数,例如:

      public void Map<T>(Func<T, string> valueGetter) where T : Control
      {
          this.Operations.Add(control => (control is T) ? valueGetter((T) control) : null);
      }
      

      在这种情况下,如果给 Button-expecting 函数一个 Label,它只会返回 null。

      【讨论】:

        猜你喜欢
        • 2014-11-29
        • 2022-05-06
        • 2017-01-21
        • 2021-12-10
        • 1970-01-01
        • 2015-10-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多