我遇到以下问题:
基类希望接收一些数据,但是数据是由派生类构造函数初始化的,在C#中,派生类构造函数在调用基构造函数之后被调用。
上下文/我要解决的问题:
让我们称之为基类Track
,它的作用是建立一个代表视频游戏轨道的网格。
派生类,例如Track1
每个都从特定的文件格式中获取跟踪数据,但有显着差异,因此禁止在基类Track
中实现整个代码。
Track
的主要工作是抽象派生类派生的数据,为此它具有派生类必须实现的抽象成员,例如: int GetVertexCount
,Vector3 GetVertex(int)
。
请多考虑一个IPicture
接口,它可以从不同的格式(例如, BMP,JPEG,然后将整个内容作为抽象返回。
我面临的问题:
在C#中,基类构造函数在派生类构造函数之前被调用,但我必须在派生的类构造函数中初始化某些内容,而该构造函数又必须传递给 base 类构造函数。在进行此操作时,我希望成员是不变的,即readonly
。
问题:
如何首先在派生类构造函数中运行一些代码,以便将结果传递给基本构造函数?
答案:
跟随 @Kit 回答,这就是我最终的做法,这很好:
具有讽刺意味的是,它最终成为了一个类似于C的API:)
答案 0 :(得分:1)
假设您不需要派生类的实例即可执行所需的逻辑,则可以在调用基本构造函数之前从派生构造函数调用静态方法。
这是一个简单的例子
public class Base
{
protected Base(SomeType data)
{
// base logic using data
}
}
public class DerivedOne : Base
{
public DerivedOne(int some, string data) : base(DerivedLogic(some, data))
{
...
}
private static SomeType DerivedLogic(int some, string data) => ...
}
public class DerivedTwo : Base
{
public DerivedTwo (string moreStuff) : base(DerivedLogic(moreStuff))
{
...
}
private static SomeType DerivedLogic(string moreStuff) => ...
}
这按以下顺序运行:
DerivedLogic
DerivedLogic
中的值)现在,这有点奇怪。更好的是,派生逻辑根本不属于派生类。我什么意思我的意思是,您有第三个类,该类传递给派生的构造函数,然后传递给基本构造函数。那会给你同样的效果。
public class Base
{
protected Base(SomeOtherType dataWrapper)
{
var data = dataWrapper.DerivedLogic();
// base logic using data
}
}
public class DerivedOne : Base
{
public DerivedOne(SomeOtherType otherType) : base(otherType)
{
...
}
}
或者在调用任何构造函数之前先计算SomeType
,然后将其传递。这两种方法中的任何一种都是更好的设计,因为它遵循SRP:
答案 1 :(得分:0)
没有一种真正优雅的方法来精确地完成您所要的东西,但是我会怀疑这是否真的必要。在构造函数中看到逻辑通常是一种代码味道。
您可以采用许多其他方法,例如使用静态Create()
方法。
class Derived : Base
{
private readonly object _o;
private Derived(object o, string s) : base(s)
{
_o = o;
}
public static Derived Create(string path)
{
var o = new object();// initialize from path
var s = o.ToString(); // get s from o.
return new Derived(o, s)
}
}
您还可以考虑在继承中使用合成:
class Base
{
private readonly string _s;
public Base(string s)
{
_s = s.ToLower();
}
}
class Derived
{
private readonly object _o;
private readonly Base _b;
public Derived(string path)
{
_o = new object();// initialize from path
_b = new Base(_o.ToString());
}
}
但是,在不知道您的实际目标和约束是什么的情况下,很难知道哪种方法合适。您已告诉我们您想如何解决问题,而不是告诉我们您要解决的问题。