C# 克服反向构造函数顺序的设计模式?

C# 克服反向构造函数顺序的设计模式?,c#,design-patterns,constructor,C#,Design Patterns,Constructor,我有以下问题: 基类希望接收一些数据,但数据是由派生类构造函数初始化的,在C#中,派生类构造函数是在调用基类构造函数之后调用的 上下文/我试图解决的问题: 让我们调用基类Track,它的作用是构建一个表示视频游戏轨迹的网格 派生类(例如,Track1每个类都从特定的文件格式获取轨迹数据,它们之间的显著差异禁止在基类track中实现整个代码 Track的主要工作是抽象从派生类传入的数据,为此,它有派生类必须实现的抽象成员,例如int-GetVertexCount,Vector3-GetVertex

我有以下问题:

基类希望接收一些数据,但数据是由派生类构造函数初始化的,在C#中,派生类构造函数是在调用基类构造函数之后调用的

上下文/我试图解决的问题:

让我们调用基类
Track
,它的作用是构建一个表示视频游戏轨迹的网格

派生类(例如,
Track1
每个类都从特定的文件格式获取轨迹数据,它们之间的显著差异禁止在基类
track
中实现整个代码

Track
的主要工作是抽象从派生类传入的数据,为此,它有派生类必须实现的抽象成员,例如
int-GetVertexCount
Vector3-GetVertex(int)

更多地考虑它是一个
ipacture
接口,可以从不同格式加载,例如BMP、JPEG,并将整个内容作为抽象返回

我面临的问题是:

在C#中,基类构造函数在派生类构造函数之前被调用,但我必须初始化派生类构造函数中的某些内容,然后我必须传递给基类构造函数。当我在上面的时候,我希望成员是不可变的,即
只读的

问题:

如何首先在派生类构造函数中运行一些代码,以便将结果传递给基构造函数

回答:

下面的@Kit回答如下:我最终做了些什么,一切都很好:


具有讽刺意味的是,它最终成为了一个类似于C的API:)

没有一种真正优雅的方式来完全满足您的要求,但我怀疑这是否真的必要。在构造函数中看到逻辑通常是一种代码味道

您还可以采取许多其他方法,比如使用静态
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());
    }       
}

但是,如果不知道您的实际目标和约束条件是什么,就很难知道这些方法中的哪一种可能是合适的。您已经告诉我们要如何解决问题,而不是要解决什么问题。

假设不需要派生类的实例来执行所需的逻辑,您可以在调用基构造函数之前从派生构造函数调用静态方法

这里有一个简单的例子

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
  • 基类构造函数(使用派生逻辑中的值)
  • 派生构造函数
  • 这有点奇怪。更好的可能是,派生逻辑根本不是派生类的一部分。我是什么意思?我的意思是你有一个第三个类,它被传递到派生构造函数,然后再传递到基构造函数。这给了你同样的效果

    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
    ,然后将其传入。这两种方法中的任何一种都是更好的设计,因为它如下所示:

  • 基类负责它所做的事情
  • 建造轨道的逻辑有这样一个单一的责任
  • 派生类有它的单一职责

  • 您可以在
    Base
    类中创建
    abstract
    virtual
    方法,并在
    \u s=s.ToLower()
    之前邀请它,然后在
    Derived
    中重写该方法。抱歉,我不够清楚,更新了我的问题,虽然您的方法确实很有趣,但我无法从该方法初始化
    只读
    字段。为什么您需要从ctor处理
    \u o
    ,只需将处理移到该方法中,并将其作为返回值返回,并在
    中使用……听起来像是一个错误。你到底想做什么?这些类不应该彼此共享层次结构。加载轨道的东西本身不是轨道。它应该生成一个轨迹,而不是加载的轨迹。只是更新了我的问题以详细解释问题。谢谢,我最终得出以下结论:
    protected track(ITrackBuilder)
    ,然后我在派生类中插入了一个适当类型的新实例。因此,基本上,我将以一堆构建器结束,但作为回报,派生的轨迹只是没有任何代码的代理。