在 C# 中的基构造函数之前执行派生构造函数
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/735138/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Execute a derived constructor before the base constructor in C#
提问by James
My problem here is that I would like to pass an object to a derived class, but it must be done before the base class constructor, since the base class will immediately call the derived class's Start()
method that uses the object.
我的问题是我想将一个对象传递给派生类,但它必须在基类构造函数之前完成,因为基类将立即调用Start()
使用该对象的派生类的方法。
Here's an excerpt from the base class, (renamed from BarcodeScannerfor convenience).
这是基类的摘录(为方便起见,从BarcodeScanner重命名)。
public abstract class MyBase
{
public MyBase()
{
if (Initialize())
this.Start();
}
public abstract bool Initialize();
public abstract void Start();
}
Here's the derived class that I'm creating.
这是我正在创建的派生类。
class MyDerived : MyBase
{
private string sampleObject;
public MyDerived (string initObject)
{
sampleObject = initObject;
}
public override bool Initialize()
{
return GetDevice();
}
public override void Start()
{
Console.WriteLine("Processing " + sampleObject.ToString());
}
}
I doubt you can make C# execute a derived constructor before the base constructor; so I'm really just looking for a solution to pass an object to the derived class before the object is used.
我怀疑您是否可以让 C# 在基构造函数之前执行派生构造函数;所以我真的只是在寻找一种在使用对象之前将对象传递给派生类的解决方案。
I've gotten around this by putting the Initialize/Start if block inside the MyDerived
constructor. However, there are other classes deriving from the base class; so I ended up having to repeat this block of Initialize/Start code in every derived class. I'd like to see an alternative to modifying the base class.
我通过将 Initialize/Start if 块放在MyDerived
构造函数中来解决这个问题。但是,还有从基类派生的其他类;所以我最终不得不在每个派生类中重复这个初始化/启动代码块。我想看到修改基类的替代方法。
采纳答案by Andrew Hare
What you are trying to do is impossible in C#. A constructor in a base class must be run before the constructor of any derived class otherwise there would be potential for corrupt object state. A child object must be able to assume that its base is fully constructed and available.
你想要做的在 C# 中是不可能的。基类中的构造函数必须在任何派生类的构造函数之前运行,否则可能会损坏对象状态。子对象必须能够假设其基础已完全构建且可用。
回答by Adam Ralph
IMHO your design is wrong. You shouldn't start the process from within the constructor. Your consuming code should explicitly call the Start() method when required.
恕我直言,你的设计是错误的。你不应该从构造函数内部开始这个过程。您的消费代码应在需要时显式调用 Start() 方法。
回答by Reed Copsey
I would rework your design so that Initialize (and potentially Start() - though I'd normally have this be a public method that's called by the user) are called after construction.
我会重新设计您的设计,以便在构造后调用 Initialize(以及可能的 Start() - 尽管我通常会将其设为由用户调用的公共方法)。
If you're making a BarcodeScanner, you could do this the first time you go to scan. Just lazy-initialize your members using the data from the derived class.
如果您正在制作 BarcodeScanner,您可以在第一次扫描时执行此操作。只需使用派生类中的数据延迟初始化您的成员。
This will work around your issue, with no real change in usage from the user.
这将解决您的问题,用户的使用不会发生真正的变化。
回答by Remco
Sorry for adding to an old thread, but maybe someone is interested in another answer. I found an (IMO) neat way to handle logic doing something more than (and after) just assigning fields in class constructors where inheritance is involved here. If you just want to have if for this specific hierarchy and not use the generic solution with an interface and an extension method, you could use the same concept in one class tree like this:
很抱歉添加到旧线程,但也许有人对另一个答案感兴趣。我找到了一种 (IMO) 巧妙的方法来处理逻辑,而不仅仅是在类构造函数中分配字段(此处涉及继承)。如果您只想针对此特定层次结构使用 if 而不想使用具有接口和扩展方法的通用解决方案,则可以在一个类树中使用相同的概念,如下所示:
public abstract class MyBase
{
protected MyBase()
{
Initialize(this) // just to illustrate this will never do anything as MyBase can never be the run time type.
}
protected bool IsInitialized { get; private set; } = false;
protected static bool Initialize<T>(T instance) where T: MyBase
{
if (instance?.GetType() == typeof(T)) // check if this is called from the constructor of instance run time type
return instance.IsInitialized || ( instance.IsInitialized = instance.Initialize() );
return false;
}
protected abstract bool Initialize();
public abstract void Start();
}
and derived:
并得出:
class MyDerived : MyBase
{
private string sampleObject;
protected bool started = false;
public MyDerived (string initObject)
{
sampleObject = initObject;
if (Initialize(this)) // if this is the most derived constructor, this will run Initialize() and return whether it was successful
this.Start();// EDIT: Just to illustrate. Normally constructors should only initialize an instance and not perform operations on it (as mentioned in other answers).
}
protected override bool Initialize()
{
return GetDevice();
}
public override void Start()
{
// if Start() would be protected, we don't need the IsInitialized property and we can move this check to the constructor on the returned value of the Initialize<T>() call.
if (!IsInitialized) throw new InvalidOperationException("Initialization failed.");
// if you want to have this method exposed public, we need to check if this instance is successfully initialized from the constructor and not in started state already.
if (started) return;
Console.WriteLine("Processing " + sampleObject.ToString());
started = true;
if (!Run(sampleObject)) started = false;
}
}