具有泛型参数约束的子类中的新虚方法

时间:2015-02-18 19:39:12

标签: c# generics inheritance

我试图了解一段简化为以下代码段的代码:

abstract class A_base {}
abstract class A_derived : A_base {}

abstract class B_base {
    protected virtual T Foo<T>() where T : A_base, new() {
        return new T();
    }
}

abstract class B_derived : B_base {
    protected new virtual T Foo<T>() where T : A_derived, new() {
        return base.Foo<T>();
    }
}

具体来说,我试图了解new virtual类中Foo方法中B_derived背后的原因。据我了解,作者想要收紧Foo方法的通用参数(从A_baseA_derived),同时让来自B_derived的类覆盖{ {1}}方法。

目前,在FooFoo

派生的任何类中,都没有覆盖B_base的实施

还有其他原因吗?这样做有什么陷阱吗?这是在重写方法中限制类型参数的常用方法吗?或者这是一种令人费解的方式,有更好的方法吗?

2 个答案:

答案 0 :(得分:1)

以下是原因:

  1. [回答使用新]请注意Foo没有被覆盖。由于重写需要相同的方法签名(包括约束)。这不是这种情况,约束正在改变,从而有效地改变了整个签名。因此,采用了新的虚拟关键字。

  2. [回答使用虚拟]现在作者想要将B_base.Foo()和B_derived.Foo视为不同的方法,如第1点所述,他还希望用户能够覆盖这些不同的方法因此需要使用Virtual关键字。

  3. 当需要更改方法的签名并且还希望允许覆盖每个单独方法的能力时,这是处理预期问题的常用方法。

答案 1 :(得分:1)

通过说new virtual,您创建了一个隐藏原始方法的新方法(不会覆盖基类版本)。这意味着从类型为B_derived的变量调用的B_derived派生的类上调用的任何方法都将使用新方法签名(和功能)。这也意味着不可能覆盖原始文件,因为它已经从方法列表中有效地删除了。

为了有一个更具体的例子,我添加了一些类和一些日志记录。

abstract class A_base {}
abstract class A_derived : A_base {}

abstract class B_base {
   public virtual T Foo<T>() where T : A_base, new() {
      Console.Write("1");
      return new T();
   }
}

abstract class B_derived : B_base {
   public new virtual T Foo<T>() where T : A_derived, new() {
      Console.Write("2");
      return base.Foo<T>();
   }
}

class C1 : A_base {}
class C2 : A_derived {}

class D1 : B_base {
   public override T Foo<T>() {
      Console.Write("3");
      return base.Foo<T>();
   }

   //override T Foo<T>() where T : A_derived, new() {
   //    //Error constraint mismatch
   //}
}

class D2 : B_derived {
   public override T Foo<T>()  {
      Console.Write("4");
      return base.Foo<T>();
   }

   //override T Foo<T>() where T : A_base, new() {
   //    //Error constraint mismatch
   //}
}




public class Program
{
   public static int Main(string[] args) {
      //Comments are what is printed out.
      var d1 = new D1();
      var d2 = new D2();
      d1.Foo<C1>(); //31
      Console.WriteLine ();
      d1.Foo<C2>(); //31
      Console.WriteLine ();
      //d2.Foo<C1>(); //Error constraint mismatch
      d2.Foo<C2>(); //421
      Console.WriteLine ();
      B_base b_d2 = d2;
      b_d2.Foo<C1>(); //1
      Console.WriteLine();
      b_d2.Foo<C2>(); //1
      Console.WriteLine ();
      return 0;
   }
}