【问题标题】:Generic method with Action<T> parameter带有 Action<T> 参数的通用方法
【发布时间】:2009-11-24 18:48:13
【问题描述】:

所以,我确信以前在某个地方已经回答了这个问题,但我在任何地方都找不到。希望一些泛型专家可以提供帮助。

public interface IAnimal{}
public class Orangutan:IAnimal{}

public void ValidateUsing<T>(Action<T> action) where T : IAnimal
{
    Orangutan orangutan = new Orangutan();
    action(orangutan);  //Compile error 1

    //This doesn't work either:
    IAnimal animal = new Orangutan();
    action(animal);  //Compile error 2
}
  1. 参数类型“猩猩”不能分配给参数类型“T”
  2. 参数类型“IAnimal”不可分配给参数类型“T”

编辑:根据 Yuriy 和其他人的建议,我可以进行一些选角,例如:

public void ValidateUsing<T>(Action<T> action) where T : IAnimal
{
    Orangutan orangutan = new Orangutan();
    action((T)(IAnimal)orangutan);

    //This doesn't work either:
    IAnimal animal = new Orangutan();
    action((T)animal);
}

我想做的是像这样调用 ValidateUsing 方法:

ValidateUsing(Foo);  

不幸的是,如果 foo 看起来像这样:

private void Foo(Orangutan obj)
{
    //Do something
}

我必须在调用 ValidateUsing 时明确指定类型

ValidateUsing<Orangutan>(Foo);

【问题讨论】:

    标签: c# generics delegates


    【解决方案1】:

    如果您应该接受任何IAnimal,为什么还要实例化Orangutan

    public void ValidateUsing<T>(Action<T> action) where T : IAnimal, new()
    {
        T animal = new T();
        action(animal);  //Compile error 2
    

    如果你重用你的泛型参数,你不会有任何类型问题...

    现在,关于为什么您的代码不起作用,您所说的只是类型 T 将派生自 IAnimal。但是,GiraffeOrangutan 一样容易,因此您不能只将OrangutanIAnimal 分配给T 类型的参数。

    【讨论】:

    • 谢谢 bdukes,我只是以猩猩为例。应该是坏的吧。我希望能够使用任何 IAnimal 调用该操作。在“真实”代码中,IAnimal 存储为类中的私有字段。所以,我并没有真正实例化任何东西。
    【解决方案2】:

    问题是,T 代表 some 类型,顺便实现了 IAnimal。

    因此,当您尝试编译 action(new Organatum()) 时会出现错误,因为您已声明该操作应采用 T 类型的参数,而该参数又可能是 Fish 类型的参数 - 您不能将 Organatum 转换为 Fish,可以吗?

    如果您想触发任何采用实现IAnimal 接口的类型参数的操作,那么只需忘记泛型并使用Action&lt;IAnimal&gt;

    HTH。

    【讨论】:

      【解决方案3】:

      进行以下更改:

      Orangutan orangutan = new Orangutan();
      action((T)(IAnimal)orangutan); 
      
      
      IAnimal animal = new Orangutan();
      action((T)animal); 
      

      【讨论】:

      • 嗨,Yuriy,这很好用。它让我参与其中(见编辑)。谢谢!
      【解决方案4】:

      试试这个。

      Orangutan orangutan = new Orangutan();
      Action<IAnimal> castedAction = action as Action<IAnimal>;
      castedAction(orangutan);
      

      【讨论】:

      • 谢谢斯坦!如果我有足够的声誉,我会赞成你的回答。
      【解决方案5】:
      public interface IAnimal { }
      public class Orangutan : IAnimal { }
      
      public void ValidateUsing<T>(Action<T> action) where T : IAnimal
      {
          Orangutan orangutan = new Orangutan();
          action((T)(orangutan as IAnimal));  // needs to be cast as IAnimal
      
          //This doesn't work either:
          IAnimal animal = new Orangutan();
          action((T)animal);  // needs to be cast as T
      }
      

      似乎它是一个界面这一事实也有所不同。如果你有一个抽象类 Animal,而不是一个接口,你可以这样做:

      public abstract class Animal { }
      public class Orangutan : Animal { }
      
      public void ValidateUsing<T>(Action<T> action) where T : Animal
      {
          Orangutan orangutan = new Orangutan();
          action(orangutan as T); 
      
          //This doesn't work either:
          Animal animal = new Orangutan();
          action(animal as T); 
      }
      

      【讨论】:

      • 您好,climbage,感谢您的详细回答。我倾向于比抽象类更频繁地使用接口(更喜欢组合与继承等等),但有趣的是它可以与抽象类一起使用。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-08-25
      • 1970-01-01
      • 1970-01-01
      • 2016-11-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多