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

时间:2011-05-04 16:44:26

标签: c# .net tdd

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

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

6 个答案:

答案 0 :(得分:48)

您可以将参数设为object

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

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

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

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

  1. 即使您没有明确指定arg的类型,您仍然可以访问它。
  2. 您可以对要允许的类型添加约束。
  3. 相反,object方法有一些重要的缺点:

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

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

      考虑以下设置:

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

      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方法时,我们不关心其参数animalDuckFishAnt还是还要别的吗。我们所关心的只是致电animal.Move()。由于我们使用where T : IAnimal约束,编译器知道我们需要知道的所有内容:

      1. 变量animal的类型为T
      2. 无论T是什么,它都会实现IAnimal
      3. 任何实施IAnimal的方法都有Move()方法。
      4. 因此,我们可以安全地致电animal.Move()
      5. (顺便说一句,是的,我们可以将DoMove写为static void DoMove(IAnimal animal),但这是另一个讨论。)

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

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

        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方法。

答案 1 :(得分:7)

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

void MyMethod<T>(T parm) { ... }

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

答案 2 :(得分:4)

void MyTestMethod<T>(T t) { }

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

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

interface IMyInterface
{
    void DoSomething();
} 

void MyTestMethod<T>(T t) where T : IMyInterface
{ 
    t.DoSomething();
}

答案 3 :(得分:3)

public void YourMethod<T>(T parameter)
{
}

答案 4 :(得分:0)

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

答案 5 :(得分:0)

将参数类型设置为“对象”,您的方法将接受每种类型作为输入。然后,您可以使用GetType()检测其类型,甚至可以使用诸如int.Parse,ToString()之类的工具,并进行类型转换以将您的输入转换为特定类型,然后使用它。

    static void whatsmytype(object place)  // Will accept any type
    {
        Type t = place.GetType(); // detects type of "place" object
        if (t.Equals(typeof(string)))
            Console.WriteLine("Type is string.");
        else if (t.Equals(typeof(int)))
            Console.WriteLine("Type is int.");
        else 
            Console.WriteLine("Type is unknown.");
    }

编辑:如果可读性并不是真正的问题,则可以用下面的代码替换方法声明行,以实现较小的速度改进:

        static void whatsmytype<T>(T place)