具有 Action<T> 参数的通用方法

9

我相信这个问题以前已经有人回答过了,但我找不到任何信息。希望一些IT技术专家能够帮忙。

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. 参数类型'Orangutan'不能分配给参数类型'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);
5个回答

7

如果你需要接受任何类型的 IAnimal,那为什么要实例化一个 Orangutan 呢?

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

如果您重复使用通用参数,就不会有任何类型问题...
现在,关于为什么您的代码不起作用,您所说的只是类型T将派生自IAnimal。然而,它同样可以是长颈鹿或者猩猩,因此您不能将Orangutan或IAnimal赋给类型T的参数。

谢谢bdukes,我只是用Orangutan作为一个例子。可能不太好。我想能够使用任何IAnimal来调用该操作。在“真实”的代码中,IAnimal被存储为类中的私有字段。所以,我并没有真正实例化任何东西。 - Matt Hornsby

4
事实上,T代表的是一种类型,该类型实现了IAnimal接口。因此,当您尝试编译action(new Organatum())时,会出现错误,因为您已经声明了action应该接受一个参数类型为T,而T本身可能是Fish等类型 - 您不能将Organatum强制转换为Fish,对吧?
如果您想触发任何需要采用实现IAnimal接口的类型作为参数的操作,则只需忘记泛型并使用Action<IAnimal>。
希望这有所帮助。

2

尝试一下这个。

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

谢谢Stan!如果我有足够的声望,我会给你点赞的。 - Matt Hornsby

2

请进行以下更改:

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


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

嗨,Yuriy,这个非常好用。它帮我解决了一部分问题(请参见编辑)。谢谢! - Matt Hornsby

0
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,感谢您提供详细的答案。我倾向于更频繁地使用接口而不是抽象类(倾向于组合而非继承等),但知道它与抽象类一起使用也很有趣。 - Matt Hornsby

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