我有很多单元测试几乎可以测试相同的行为。但是,数据类型会发生变化。
我正在尝试创建一个可以采用任何数据类型的通用方法。我尝试将输入参数设为 var,但这是不允许的。此外,查看了 c# 泛型,但通常处理一个列表。
您可以将参数设为object:
object
public void DoSomething(object arg) { //...
或者你可以做我喜欢的事情并制作一个通用方法:
public void DoSomething<T>(T arg) { //...
通用方法有两个主要优点,我将举例说明它们为何有用:
arg
相反,该object方法有一些重要的缺点:
DoSomething
向泛型方法添加类型约束允许您限制该方法,使其仅接受某些类型。为什么有用?因为即使您不知道或不关心您正在使用的特定类型,您现在也知道一些关于它的信息,并且您可以使用这些信息。
考虑以下设置:
public interface IAnimal { void Move(); } public class Duck : IAnimal { public void Move() { Console.WriteLine("Flying"); } } public class Fish : IAnimal { public void Move() { Console.WriteLine("Swimming"); } } public class Ant : IAnimal { public void Move() { Console.WriteLine("Walking"); } }
由于我们有一个IAnimal接口,我们可以编写针对以下任何实现的通用方法IAnimal:
IAnimal
public class Program { static void DoMove<T>(T animal) where T : IAnimal { animal.Move(); } public static void Main(string[] args) { Duck duck = new Duck(); Fish fish = new Fish(); Ant ant = new Ant(); DoMove<Duck>(duck); DoMove<Fish>(fish); DoMove<Ant>(ant); } }
运行它:http ://rextester.com/GOF1761
当我们编写DoMove方法时,我们并不关心它的参数animal是 a Duck、 a Fish、 anAnt还是其他任何东西。我们关心的只是打电话animal.Move()。由于我们使用了where T : IAnimal约束,编译器知道我们需要它知道的一切:
DoMove
animal
Duck
Fish
Ant
animal.Move()
where T : IAnimal
T
Move()
(顺便说一句,是的,我们可以写DoMove为static void DoMove(IAnimal animal),但这是另一个讨论。)
static void DoMove(IAnimal animal)
好吧,但让我们更进一步。在许多情况下,您可以调用泛型方法而无需指定它们的类型参数。这称为类型推断,除了为您节省一些输入之外,它在对不同类型的对象执行相同操作时也很有用。
public static void Main(string[] args) { IAnimal[] animals = new IAnimal[] { new Duck(), new Fish(), new Ant() }; foreach (IAnimal animal in animals) { DoMove(animal); } }
运行它:http ://rextester.com/OVKIA12317
您只需编写DoMove<T>一次该方法,就可以在任何类型上调用它,IAnimal而无需提供更具体的类型。每次都会调用适当版本的 Move,因为DoMove<T>能够推断要使用哪种类型T。当您调用 时DoMove(duck),.NET 会理解您的真正意思DoMove<Duck>(duck),然后调用该类Move上的方法。Duck
DoMove<T>
DoMove(duck)
DoMove<Duck>(duck)
Move