C# 强制派生类使用参数实现基类构造函数
是否可以对需要实现构造函数(带参数)的派生类强制执行编译时约定? 我有一个基类,它的构造函数需要一个参数:C# 强制派生类使用参数实现基类构造函数,c#,.net,C#,.net,是否可以对需要实现构造函数(带参数)的派生类强制执行编译时约定? 我有一个基类,它的构造函数需要一个参数: public class FooBase { protected int value; public FooBase(int value) { this.value = value; } public virtual void DoSomething() { throw new NotImplementedException(); } } 我想强制基类的派生实现相同的构造函数
public class FooBase
{
protected int value;
public FooBase(int value) { this.value = value; }
public virtual void DoSomething() { throw new NotImplementedException(); }
}
我想强制基类的派生实现相同的构造函数:
public class Foo : FooBase
{
public Foo(int value) : base(value) { }
public override void DoSomething() { Console.WriteLine("Foo: {0}", value); }
}
如果未实现构造函数,则派生类会导致编译器错误,因为基类中没有默认构造函数:
// 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); }
}
在派生类中添加默认构造函数FooBar()可以使编译器错误静音,但提供了一种危险的方法,可以在不初始化所需基类int值的情况下实例化FooBar。因为我使用的是工厂(见下文),所以沉默编译器错误只会在以后导致运行时错误。我想强制FooBar实现FooBar(int)
有趣的观察:
如果将默认构造函数FooBase()添加到FooBase,则它将由不提供构造函数的派生类“继承”:
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.
}
因为我使用的是工厂,而不是如图所示的直接实例化,所以没有编译器错误。相反,我得到一个运行时异常:“找不到类型上的构造函数。”
不可行的解决方案:
- 接口不支持构造函数
- 构造函数不能是虚拟的或抽象的
- 在基类中提供默认构造函数以及传递设置参数的属性
public class Foo : FooBase
{
public Foo(int value) : base(value) { }
public override void DoSomething() { Console.WriteLine("Foo: {0}", value); }
}
这是不正确的-构造函数通常不会被继承。默认构造函数会自动为不提供任何其他构造函数实现的类提供
您可以在为您提供Init()方法的接口上添加约束:
public interface IInit
{
void Init(int someValue);
}
public class FooBase : IInit
{
..
}
你试过了吗
public class FooBase
{
protected int value;
private FooBase(){}
public FooBase(int value) { this.value = value; }
public virtual void DoSomething() { throw new NotImplementedException(); }
}
私有构造函数阻止了无参数构造函数的选项。似乎我不明白你的意思,或者你的意思是错误的 出现以下情况会导致编译器错误:
public class FooBase
{
protected int value;
public FooBase(int value) { this.value = value; }
public virtual void DoSomething() { throw new NotImplementedException(); }
}
public class Foo : FooBase
{
public Foo(int value) : base(value) { }
public override void DoSomething() { Console.WriteLine("Foo: {0}", value); }
}
public class FooBar : FooBase
{
public FooBar() // <----------------- HERE telling 'Test.FooBase' does not contain a constructor that takes 0 arguments
{
}
public override void DoSomething() { Console.WriteLine("FooBar: {0}", value); }
}
公共类FooBase
{
保护整数值;
公共FooBase(int值){this.value=value;}
公共虚拟void DoSomething(){throw new NotImplementedException();}
}
公共类Foo:FooBase
{
公共Foo(int值):基(值){}
public override void DoSomething(){Console.WriteLine(“Foo:{0}”,value);}
}
公共类FooBar:FooBase
{
public FooBar()//如果只为构造函数提供基类上的参数,则派生类在构造时必须调用该参数。但是,这并不强制它如何调用。可以使用一些默认值调用它,也可以从其他构造函数参数计算值
构造函数不是继承的。相反,当您在类中不指定任何构造函数时,会发生什么情况(结构的行为不同),将创建一个公共无参数构造函数,该构造函数调用基类的无参数构造函数。当然,如果基类没有此类构造函数,则不会发生这种情况,在这种情况下,您必须自己指定构造函数
正如@BrokenGlass所提到的,强制这样一个约束的唯一方法是在基类上有一个抽象方法Init()
(可能来自接口)。我认为一般来说,这种做法不是好的OOP设计(对象应该在创建后可用,而不需要调用其他方法),但在这种情况下,它可能是最好的解决方案。正如其他人所指出的,接口方法,如Init()有点尴尬。接口应该公开行为,而不是内部需求。对象的内部状态有助于实现该行为。类通常是包装状态和行为的一种方式。构造函数公开内部需求,但接口“服务”的使用者不关心这个;他们只关心行为:
interface IFoo
{
void DoSomething();
}
所以很自然,不同的实现需要不同的构造函数,因为它们通常需要不同的内部状态来实现IFoo.DoSomething
然后,您遇到的问题是如何编写通用代码,知道如何实例化所有这些不同类型。通常使用Activator.CreateInstance上的工厂方法和变体以特殊方式完成此任务。我鼓励您考虑一些更优雅地解决此问题的备选方案:
- IoC/DI容器通常是一种更好的方法,因为它们标准化了这些技术,性能更好,并带来了许多附加功能
- 在.NET4中,托管可扩展性框架(MEF,也称为System.ComponentModel.Composition)具有一组重叠的功能,具有许多相同的优点,特别适合插件设计
正确。这就是为什么我在“继承”周围加上单引号的原因,目的是将其表示为对该术语的错误使用。其效果是基本构造函数