c# – 具有继承和通用约束的两步方法解析

前端之家收集整理的这篇文章主要介绍了c# – 具有继承和通用约束的两步方法解析前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
在使用带继承的泛型约束时,我遇到了一些非常令人惊讶的事情.我有一个重载的方法Foo与参数不同 – 基本或派生类实例.在这两种情况下,它通常只是将实例传递给第二对重载方法 – Bar.

当我用基类实例调用Foo时,会调用基类的Bar重载.当我使用派生类实例调用Foo时,将调用派生类的Bar重载.这是明确和预期的.

但是当我尝试将Foo方法合并到使用泛型和约束的单个GenericFoo时,方法的解析也不同 – T被正确解析,但只调用了Bar的基类重载.

  1. public class Animal { }
  2. public class Cat : Animal { }
  3.  
  4. public class AnimalProcessor
  5. {
  6. public static void Foo(Animal obj)
  7. {
  8. Console.WriteLine("Foo(Animal)");
  9. Bar(obj);
  10. }
  11.  
  12. public static void Foo(Cat obj)
  13. {
  14. Console.WriteLine("Foo(Cat)");
  15. Bar(obj);
  16. }
  17.  
  18. // new generic method to replace the two above
  19. public static void GenericFoo<T>(T obj)
  20. where T : Animal
  21. {
  22. Console.WriteLine("Foo(generic)");
  23. Bar(obj);
  24. }
  25.  
  26. public static void Bar(Animal obj)
  27. {
  28. Console.WriteLine("Bar(Animal)");
  29. }
  30.  
  31. public static void Bar(Cat obj)
  32. {
  33. Console.WriteLine("Bar(Cat)");
  34. }
  35. }

测试代码 – 非通用旧方法的两个第一种情况,新通用方法的两种情况.

  1. Console.WriteLine("Animal()");
  2. AnimalProcessor.Foo(new Animal());
  3. Console.WriteLine();
  4.  
  5. Console.WriteLine("Cat()");
  6. AnimalProcessor.Foo(new Cat());
  7. Console.WriteLine();
  8.  
  9. Console.WriteLine("Animal()");
  10. AnimalProcessor.GenericFoo(new Animal());
  11. Console.WriteLine();
  12.  
  13. Console.WriteLine("Cat()");
  14. AnimalProcessor.GenericFoo(new Cat());
  15. Console.ReadLine();

结果 – 注意Bar中解决的类型差异:

  1. Animal()
  2. Foo(Animal)
  3. Bar(Animal)
  4.  
  5. Cat()
  6. Foo(Cat)
  7. Bar(Cat)
  8.  
  9. Animal()
  10. Foo(generic)
  11. Bar(Animal)
  12.  
  13. Cat()
  14. Foo(generic)
  15. Bar(Animal)

看起来编译器将所有来自GenericFoo的调用绑定到最不具体的重载,即使在编译时已知所有更具体类型的调用.为什么会这样,这种行为的原因是什么?哪部分规格定义了这个?

解决方法

根据OP的要求,评论重新发布为答案:

泛型不是模板.通用方法编译一次,它们的行为是针对“最通用”的情况(在本例中为Animal).这与C样式模板不同,其中模板是按类型为每个特化分别编译的.

猜你在找的C#相关文章