让方法采用c#中的任何数据类型

我有很多unit testing,几乎测试相同的行为。 但是,数据类型会发生变化

我正在尝试创建一个可以采用任何数据类型的通用方法。 我尝试制作输入参数var但不允许这样做。 另外,查看c#generics但通常会处理列表。

您可以将参数设为object

 public void DoSomething(object arg) { //... 

或者你可以做我喜欢的事情并制作一个通用的方法:

 public void DoSomething(T arg) { //... 

通用方法有两个主要优点,我将举例说明它们有用的原因:

  1. 即使您没有明确指定arg的类型,您仍然可以访问它。
  2. 您可以对要允许的类型添加约束。

相反, object方法有一些重要的缺点:

  1. 由于您将arg视为object ,因此您只能对任何对象执行操作。
  2. 如果将值类型作为object参数传递,则该变量将被加框 ,这意味着性能受到影响。 这不是一个巨大的打击,但如果你连续几次打电话给DoSomething ,你可能会开始感受它。

generics和类型约束

向generics方法添加类型约束允许您限制方法,使其仅接受某些类型。 为什么这有用? 因为即使您不了解或关心您正在使用的具体类型,您现在对它有所了解,并且您可以使用该信息。

请考虑以下设置:

 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 任何实现的generics方法:

 public class Program { static void DoMove(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); DoMove(fish); DoMove(ant); } } 

运行它: http : //rextester.com/GOF1761

当我们编写DoMove方法时,我们不关心它的参数animalDuckFishAnt还是其他任何东西。 我们关心的只是调用animal.Move() 。 由于我们使用where T : IAnimal约束,编译器知道我们需要它知道的一切:

  1. 可变animalT型。
  2. 无论T是什么,它都实现了IAnimal
  3. 任何实现IAnimal东西都有一个Move()方法。
  4. 因此,我们可以安全地调用animal.Move()

(顺便说一句,是的,我们可以把DoMove写成static void DoMove(IAnimal animal) ,但这是另一个讨论。)

类型推断(及其一些含义)

很好,但让我们更进一步。 在许多情况下,您可以调用generics方法而无需指定其类型参数。 这称为类型推断 ,除了为您节省一些输入外,在对不同类型的对象执行相同操作时也很有用。

 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方法,并且可以在任何类型的IAnimal上调用它,而无需提供更具体的类型。 每次都会调用相应的Move版本,因为DoMove能够推断出哪种类型用于T 当你调用DoMove(duck) ,.NET理解你真的是指DoMove(duck) ,然后调用Duck类的Move方法。

您可以将object作为参数类型。 或许更好的是使用generics:

 void MyMethod(T parm) { ... } 

这样,参数实际上是用户传入的类型 – 它不像object和值类型那样加框。

 void MyTestMethod(T t) { } 

为您提供通用的测试方法,但我无法想象任何有用的方法。 你需要测试什么? 你怎么知道T型有这些方法? T可以是上述方法中的任何类型。 在上面的例子中你可以从t调用的唯一方法是object的常用方法。

您真正需要做的是确定针对您要测试的一种或多种类型的常见行为 ,并通过接口定义该行为的语法契约。 然后,您可以将通用测试方法限制为仅接受实现该接口的类型。

 interface IMyInterface { void DoSomething(); } void MyTestMethod(T t) where T : IMyInterface { t.DoSomething(); } 
 public void YourMethod(T parameter) { } 

尝试使用动态关键字,只要您的所有不同类型具有unit testing使用的相同方法,这将起作用,否则您将获得运行时exception