让方法采用c#中的任何数据类型
我有很多unit testing,几乎测试相同的行为。 但是,数据类型会发生变化
我正在尝试创建一个可以采用任何数据类型的通用方法。 我尝试制作输入参数var但不允许这样做。 另外,查看c#generics但通常会处理列表。
您可以将参数设为object
:
public void DoSomething(object arg) { //...
或者你可以做我喜欢的事情并制作一个通用的方法:
public void DoSomething(T arg) { //...
通用方法有两个主要优点,我将举例说明它们有用的原因:
- 即使您没有明确指定
arg
的类型,您仍然可以访问它。 - 您可以对要允许的类型添加约束。
相反, object
方法有一些重要的缺点:
- 由于您将
arg
视为object
,因此您只能对任何对象执行操作。 - 如果将值类型作为
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
方法时,我们不关心它的参数animal
是Duck
, Fish
, Ant
还是其他任何东西。 我们关心的只是调用animal.Move()
。 由于我们使用where T : IAnimal
约束,编译器知道我们需要它知道的一切:
- 可变
animal
是T
型。 - 无论
T
是什么,它都实现了IAnimal
。 - 任何实现
IAnimal
东西都有一个Move()
方法。 - 因此,我们可以安全地调用
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
类的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