【问题标题】:How to make base constructor neccessary to call?如何使基础构造函数必须调用?
【发布时间】:2017-08-17 03:36:54
【问题描述】:

问题

如何使基础构造函数在派生类中调用。当您不实现抽象方法时,IDE 会显示错误消息,并且您理解应该实现这个:) 当程序员不调用 base() 时,我想要一些消息。此外,如果层次结构很深,我需要调用第一个基类构造函数。也许有一些解决方法可以自动进行此调用,或者有一些解决方案可以让程序员说他需要进行此调用。如您所见,在abstract class Shape 构造函数中调用了此设置方法SetShapeWorker。我需要在所有派生类中调用这个构造函数。

说明

我有形状。我决定用命令模式实现一些算法,所以 Shape 是接收器。在这种情况下,它也是一个调用者,因为在某些方法中我需要从 ShapeWorker 调用一些方法。这里是SizeDialog。查看Shape 中的构造函数,我有shapeWorker 变量,我在一些Shape 方法中使用该方法-查看SetSizeWorker() 的默认实现。

我想用具体的接收器——方形或矩形来初始化 ShapeWorker。所以我声明了astract SetShapeWorker,如果另一个程序员或者我在几周后添加了三角形,IDE 将显示我需要实现受保护的 SetShapeWorker 的消息,程序员应该明白他需要写这样的东西:

class Triangle : Shape {
    //adding the triangle shape worker
    public override SetShapeWorker() {
        shapeWorker = new ShapeTriangleWorker();
        shapeWorker.SetReceiver(this);
    }
}

在此之后,所有命令调用程序方法都应该工作。如您所见,此 set 方法在 abstract class Shape 构造函数中调用。所以我想在所有派生类中调用这个构造函数。

以及我进行此初始化的原因:使用演员表(receiver as Rectangle).SetSize(a,b)(receiver as Square).SetSize(a)。 Bob叔叔在其中一个视频中说,要进行这些演员表,我应该确保演员表是有效的,我同意他的观点:) 我尝试将其设置为专用于用户界面SetShapeWorker,程序员应该设置具体的接收器。

代码

abstract class Shape {
    private ShapeWorker shapeWorker;    
    public Shape() {
        SetShapeWorker();
    }
    private bool isSet = false;
    public IsSet {
        get {
            return isSet;
        }
    }
    public abstract int Square();
    protected abstract void SetShapeWorker();
    public void SetSizeWorker() {
        if(shapeWorker != null) {
            shapeWorker.SizeDialog();
        }
    }
}
class Square : Shape {
    private int a;
    public Square() {

    }
    public SetSize(int a) {
        this.a = a;
        isSet = true;
    }
    public override int Square() {
        return a*a;
    }
    protected override SetShapeWorker() {
        shapeWorker = new ShapeSquareWorker();
        shapeWorker.SetReceiver(this);    
    }
}
class Rectangle : Shape {
    private int a, b;
    private Rectangle() : base() {
    }
    public SetSize(int a, int b) {
        this.a = a;
        this.b = b;
        isSet = true;
    }
    public override int Square() {
        return a*b;
    }
    protected override SetShapeWorker() {
        shapeWorker = new ShapeRectangleWorker();
        shapeWorker.SetReceiver(this);    
    }
}

abstract class ShapeWorker 
{
    public Shape receiver;
    public abstract void SetReceiver(Shape receiver) {
        this.receiver = receiver;
    }
    public abstract void SizeDialog();
    public abstract int StrangeCountSquare();
    public int getDeltaSquare() {
        if(receiver.IsSet == false) {
            SizeDialog();            
            return StrangeCountSquare();
        }
    }
}
class ShapeSquareWorker {
    public override void SizeDialog() {
        int a;
        Console.WriteLine("Enter the a: ");
        Int32.TryParse(Console.ReadLine(), out a);
        (receiver as Square).SetSize(a);
    }

    public override int StrangeCountSquare() {
        return receiver.Square() + 10;
    }
}
class ShapeRectangleWorker {
    public override void SizeDialog() {
        int a, b;
        Console.WriteLine("Enter the a: ");
        Int32.TryParse(Console.ReadLine(), out a);
        Console.WriteLine("Enter the b: ");
        Int32.TryParse(Console.ReadLine(), out b);
        (receiver as Rectangle).SetSize(a,b);
    }

    public override int StrangeCountSquare() {
        return receiver.Square() + 20;        
    }
}

顺便说一句 现在我正在学习 SOLID 和模式,stackoverflow 中最适合讨论的地方在哪里? F.e.如果我想讨论混合一些模式的有用方法。请在评论中回答。

【问题讨论】:

  • 可能ShapeSquareWorkerShapeRectangleWorker 应该是ShapeWorker 的派生词...
  • 我不确定我是否遵循,但是当您在基类中有一个构造函数时,它将始终被调用,无论开发人员是否将其显式化。
  • 你的代码有什么问题?将调用 SetShapeWorker,因为将在基类中调用默认构造函数。
  • 在 .NET 的基类中调用构造函数不是可选的。您可以指定调用哪一个,但如果不指定,则将调用默认的无参数构造函数。如果你没有那个,并且没有指定要调用哪个其他构造函数,那么你的派生类会出现编译器错误。你还想要什么?你想要求程序员显式写出对base()的调用,即使编译器会为你注入它?
  • 我只是注意到你的设计中有一个Anti-patternCircular DependencyShape 指的是ShapeWorkerShapeWorker 指的是Shape。这不是正确的 OO。

标签: c# oop inheritance design-patterns constructor


【解决方案1】:

如果您在基类中只有一个默认构造函数,我认为您误解了事情是如何工作的。它总是在创建派生类时被调用,即使它没有被显式调用:

using System;

namespace ConsoleApp2
{
    public abstract class Base
    {
        public Base()
        {
            Console.WriteLine("Base constructor called.");
        }
    }

    public class Derived : Base
    {
    }

    class Program
    {
        static void Main()
        {
            Derived d = new Derived(); // Prints "Base constructor called."
        }
    }
}

另外,如果将基类的默认构造函数替换为非默认构造函数,如果不从派生类调用它,则会出现编译错误。

如果基类中同时有默认和非默认构造函数,那么如果派生类构造函数没有调用非默认构造函数,则会自动调用基类默认构造函数:

using System;

namespace ConsoleApp2
{
    public abstract class Base
    {
        public Base()
        {
            Console.WriteLine("Default base constructor called.");
            Value = -1;
        }

        public Base(int value)
        {
            Console.WriteLine("Non-default base constructor called.");
            Value = value;
        }

        public int Value;
    }

    public class Derived : Base
    {
    }

    class Program
    {
        static void Main()
        {
            Derived d = new Derived(); // Prints "Default base constructor called."
        }
    }
}

如果你想让基类有一个默认构造函数用于自己的实现目的,但强制派生类使用非默认构造函数,那么你可以让基类默认构造函数private

如果这样做,如果任何派生类构造函数未能调用基类非默认构造函数,则会出现编译错误。

【讨论】:

    猜你喜欢
    • 2022-12-03
    • 2020-11-15
    • 1970-01-01
    • 2010-09-21
    • 1970-01-01
    • 1970-01-01
    • 2014-07-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多