强制继承类构造函数C#中的部分基初始化(和方法)(就像抽象对方法所做的那样)-解决这个问题

本文关键字:方法 抽象 问题 解决 初始化 继承 构造函数 | 更新日期: 2023-09-27 18:29:13

我有一个C#abstract类,它的子类要实现一些方法。

尽管如此,这些子级的初始化值由两部分组成:一部分与父级相同,另一部分对子级唯一。

public abstract class parentClass {
    public abstract bool IsInputValid(string input); //children must implement this
    public parentClass () {
       //Some shared initialization
    }
}

如果类不是abstract,我们可以这样做来实现

public class parentClass {
    public parentClass (string input) {
       //Some shared initialization
    }
}
public class childClass : parentClass {
    public childClass (string input) : base (input) {
       //Some unique initialization
    }
}

但这不能使用abstract类和其他一些类来完成,该方法不需要实现(因为它不是抽象的)。

所以我在这里左右为难。一方面,我希望调用一些基本初始化,另一方面,也希望强制执行一些方法。

所以我的问题是,我们通常如何实现这种情况?一方面,它强制执行一些基本初始化,另一方面,强制执行一些方法。

注意:我是abstract类的新手,所以我很高兴收到任何关于它的输入。

我在哪里申报错误(如果有的话)?如果我们不能做到这一点,是否有一种方法可以产生相同的结果(即强制子类为构造函数使用特定的签名)?

强制继承类构造函数C#中的部分基初始化(和方法)(就像抽象对方法所做的那样)-解决这个问题

不需要强制执行。您说基类有一些常见的初始化,子类也有自己的专用初始化。

这已经被强制执行了,如果你有这个:

public abstract class Base
{
    protected Base(int value) { ... }
}

然后你有几个保证:

  • 没有人可以构造Base类型的对象,因为它是抽象的
  • 如果不间接调用Base的唯一现有构造函数(该构造函数接受int value参数),任何人都无法构造从Base继承的对象

最后一部分很重要。

子类至少可以通过三种方式处理这种类型的基构造函数:

  • 它可以提供一个看起来完全相同的构造函数——保存它的名称,只需将值传递给基本构造函数:

    public class Child : Base
    {
        public Child(int value) : base(value) { ... }
    }
    
  • 它可以提供一个具有此参数的构造函数,但也有子类构造函数的附加参数:

    public class Child : Base
    {
        public Child(int value, string other) : base(value) { ... }
    }
    
  • 它可以提供一个构造函数,该构造函数没有基类的参数,但能够计算这个参数:

    public class Child : Base
    {
        public Child(string other) : base(other.Length) { ... }
    }
    

最后一部分还处理了子构造函数根本没有参数的情况:

public class Child : Base
{
    public Child() : base(new Random().Next(100)) { ... }
}

无论使用哪种方法,都不可能在不传递该参数值的情况下调用基类构造函数,因此必须强制执行以下操作:

  • 子类必须知道基类构造函数及其参数

但是,您不能也不应该尝试使用特定签名来强制特定构造函数的存在。


话虽如此,如果你想创建一种通用的方法来构建两个不同的子类,这两个子类有着如此不同的构造函数,那么使用它们的代码不需要知道任何一个构造函数的细节呢?

输入工厂模式(维基百科):

在基于类的编程中,工厂方法模式是一种创建模式,它使用工厂方法来处理创建对象的问题,而不必指定将要创建的对象的确切类。这是通过调用工厂方法(在接口中指定并由子类实现,或者在基类中实现并可选地由派生类重写)而不是通过调用构造函数来创建对象来实现的。

(引用自维基百科文章中条目段落的文本)

这里有一种方法可以抽象出这些不同构造函数和子类的存在和知识:

void Main()
{
    Test(new Child1Factory());
    Test(new Child2Factory());
}
public void Test(IBaseFactory baseFactory)
{
    Console.WriteLine("In Test(...");
    var b = baseFactory.Create();
}
public class Base
{
    public Base(int value)
    {
        Console.WriteLine($"Base.ctor({value})");
    }
}
public interface IBaseFactory
{
    Base Create();
}
public class Child1 : Base
{
    public Child1(int value) : base(value)
    {
        Console.WriteLine($"Child1.ctor({value})");
    }
}
public class Child1Factory : IBaseFactory
{
    public Base Create() => new Child1(42);
}
public class Child2 : Base
{
    public Child2(string name) : base(name.Length)
    {
        Console.WriteLine($"Child2.ctor({name})");
    }
}
public class Child2Factory : IBaseFactory
{
    public Base Create() => new Child2("Meaning of life");
}

请特别注意Test(...)方法,因为它不知道它将得到哪个Base子对象,也不知道如何构造这样的对象。如果以后从Base添加新的子类型,则还必须提供新的工厂,但使用这些工厂的现有代码不需要更改。

如果你想要一个更简单的工厂模式,你所要做的就是用一个委托来替换接口和工厂类:

void Main()
{
    Test(() => new Child1(42));
    Test(() => new Child2("Meaning of life"));
}
public void Test(Func<Base> baseFactory)
{
    Console.WriteLine("In Test(...");
    var b = baseFactory();
}

最后一点。由于工厂模式意味着您必须创建一个不同的类型来进行对象的实际构造,因此您可以通过强制执行其他类型的签名

  • 在工厂接口上为Create方法添加参数
  • 指定具有工厂代理参数的代理

这意味着您可以强制执行"创建过程"的签名。尽管如此,您不能强制特定构造函数的存在或签名,但构造函数只是达到目的的一种手段,创建一个对象,使用工厂模式,您实际上可以在代码中形式化该模式,因此您应该得到您想要的。

您不能强制签名,甚至不能强制存在派生类的构造函数(或任何类别)

恐怕故事到此为止了。你没有做错什么,只是不可能。

由于不能重写c#中的构造函数,因此不能强制派生类中存在某个构造函数。

这意味着:

  • 构造函数不能是抽象的、虚拟的等
  • 构造函数不是多态的

不能有抽象构造函数,但也不需要。你所需要做的就是从parentClass中删除"abstract"关键字,你就可以开始了。