c# - 在 Inherited Class Constructor C# 中强制部分基初始化(和方法)(就像抽象对方法所做的那样)——解决这个问题

标签 c# inheritance constructor abstract-class

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

尽管如此,这些子项的初始化值由两部分组成:一部分与父项相同,另一部分是子项所独有的。

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

如果类不是抽象的,我们可以做这样的事情来实现它

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 类的新手,所以我很乐意收到有关它的任何意见。

我在哪里申报错误(如果有)?如果我们不能这样做,是否有办法绕过产生相同的结果(即强制子类对构造函数使用特定签名)?

最佳答案

应该没有必要强制执行此操作。你说基类有一些共同的初始化,子类也有自己专门的初始化。

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

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

那么你有几个保证:

  • 没有人可以构造 Base 类型的对象,因为它是抽象的
  • 如果不间接调用 Base 的唯一现有构造函数,没有人可以构造继承自 Base 的对象,该构造函数采用 int value 参数。

最后一部分很重要。

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

  • 它可以提供一个看起来完全相同的构造函数,只是将值传递给基础构造函数:

    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)) { ... }
}

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

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

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


现在,话虽如此,如果您想创建某种通用方法来构造两个具有如此不同构造函数的不同子类,并且使用它们的代码不需要知 Prop 体细节,该怎么办任何一个构造函数?

输入 factory pattern (Wikipedia) :

In class-based programming, the factory method pattern is a creational pattern that uses factory methods to deal with the problem of creating objects without having to specify the exact class of the object that will be created. This is done by creating objects by calling a factory method—either specified in an interface and implemented by child classes, or implemented in a base class and optionally overridden by derived classes—rather than by calling a constructor.

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

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

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 添加新的子类型,您还必须提供新的工厂,但不需要更改使用这些工厂的现有代码。

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

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();
}

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

  • 在工厂接口(interface)的Create方法中添加参数
  • 为工厂委托(delegate)指定一个具有参数的委托(delegate)

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

关于c# - 在 Inherited Class Constructor C# 中强制部分基初始化(和方法)(就像抽象对方法所做的那样)——解决这个问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34632506/

相关文章:

c# - 选择多个 CSV 并批量写入数据库

c# - MySqlProfileProvider 无法连接到我的数据库

c++ - 为什么不能在派生类的构造函数初始化列表中初始化基类的数据成员?

c++ - 抽象类的用户定义构造函数

c# - LINQ 中按子表分组

c# - ASP.Net Core 1.1 解决方案中检测到自引用循环

c++ - 在指针c++中如何使用继承类的实际功能

c# - 如何检查该类型是从某些接口(interface)继承的 C#

c# - 接口(interface)与抽象类

java - 重载子类的构造函数