强制派生类用参数实现基类构造函数

Kev*_*ice 16 .net c#

是否可以对需要实现构造函数(带参数)的派生类强制执行编译时合同?

我有一个基类与构造函数需要一个参数:

public class FooBase
{
  protected int value;
  public FooBase(int value) { this.value = value; }
  public virtual void DoSomething() { throw new NotImplementedException(); }
}
Run Code Online (Sandbox Code Playgroud)

我想强制我的基类的派生实现相同的构造函数:

public class Foo : FooBase
{
  public Foo(int value) : base(value) { }
  public override void DoSomething() { Console.WriteLine("Foo: {0}", value); }
}
Run Code Online (Sandbox Code Playgroud)

如果没有实现构造函数,派生类会导致编译器错误,因为基类中没有默认构造函数:

// ERROR: 'Does not contain a constructor that takes 0 arguments'
// Adding default constructor in FooBase eliminates this compiler error, but
// provides a means to instantiate the class without initializing the int value.
public class FooBar : FooBase
{
  public override void DoSomething() { Console.WriteLine("FooBar: {0}", value); }
}
Run Code Online (Sandbox Code Playgroud)

在派生类中添加默认构造函数FooBar()会使编译器错误无效,但是提供了一种实例化FooBar的危险方法,而不需要初始化所需的基类int值.因为我正在使用工厂(见下文),所以静默编译器错误只会导致稍后的运行时错误.我想强制FooBar实现FooBar(int)

有趣的观察:

如果将默认构造函数FooBase()添加到FooBase,那么它将由不提供构造函数的派生类"继承":

  1. Foo不继承默认构造函数,因为它提供了显式构造函数.
  2. FooBar DOES继承了FooBase().

但是,非默认构造函数FooBase(int)也是如此!

  1. Foo必须显式实现FooBase(int)并调用base(int).
  2. FooBar FAILS'继承'非默认构造函数的方式与继承默认构造函数的方式相同!

我不想在基类中使用默认构造函数,因为实例是使用提供所需"设置"参数的工厂方法创建的.此处未说明该工厂方法(使用Activator.CreateInstance()方法).

以下是派生类应该实例化的方式:

  static void Main(string[] args)
  {
    FooBase myFoo = new Foo(4);     // Works, since Foo(int) is implemented.

    // ERROR: 'Does not contain a constructor that takes 1 arguments'
    FooBase myFooBar = new FooBar(9);  // Fails to compile.
  }
Run Code Online (Sandbox Code Playgroud)

因为我使用的是工厂 - 而不是如图所示的直接实例化 - 所以没有编译器错误.相反,我得到一个运行时异常:'找不到类型的构造函数.'

不可行的解决方案:

  • 接口不支持构造函数.
  • 构造函数不能是虚拟的或抽象的.

似乎提供基类不能强制构造函数的合同.

解决方法:

  • 在基类中提供默认构造函数以及要传递设置参数的属性.

Bro*_*ass 9

如果将默认构造函数FooBase()添加到FooBase,那么它将由不提供构造函数的派生类"继承":

这是不正确的 - 一般来说构造函数永远不会被继承.为不提供任何其他构造函数实现的类自动提供默认构造函数.

您可以在为您提供Init()方法的接口上设置约束:

public interface IInit
{
   void Init(int someValue);
}

public class FooBase : IInit
{
   ..
}
Run Code Online (Sandbox Code Playgroud)


Ahm*_*gdy 9

你试过了吗

public class FooBase
{
  protected int value;
  private FooBase(){}
  public FooBase(int value) { this.value = value; }
  public virtual void DoSomething() { throw new NotImplementedException(); }
}
Run Code Online (Sandbox Code Playgroud)

私有构造函数阻止无参数构造函数的选项