C# 继承混淆

本文关键字:继承 | 更新日期: 2023-09-27 18:35:10

我正在尝试实现基类和派生类的调用方法。但是,如果我做得正确,我有点困惑。我想从基类中设置值并在派生类中使用它们。

namespace Inheritance
{
    using System;
    public class BaseClass
    {
        public BaseClass() { }
        protected string methodName;
        protected int noOfTimes;
        public void Execute(string MethodName, int NoOfTimes)
        {
            this.methodName = MethodName;
            this.noOfTimes = NoOfTimes;
        }
    }
    public class DerivedClass : BaseClass
    {
        public DerivedClass() : base() { }
        public void Execute()
        {
            Console.WriteLine("Running {0}, {1} times", base.methodName, base.noOfTimes);
        }
    }
    public class Program
    {
        static void Main(string[] args)
        {
            DerivedClass d = new DerivedClass();
            d.Execute("Func", 2);
            d.Execute();
            Console.ReadLine();
        }
    }
}

问题:我是否可以仅使用 1 次调用来执行而不是 2 次实现上述相同?

我希望我上面的例子很清楚。如果不是这样,请告诉我,我将提供更多详细信息。

谢谢

C# 继承混淆

免责声明 ,我的回答假设您想要一个围绕方法继承及其实现的解决方案。提供的其他答案也是该问题的良好解决方案。

听起来您想重写派生类中的方法。为此,基类需要将方法标记为virtualabstract。但是,在您的情况下,派生类方法签名是不同的。我将假设这是一个不了解它如何工作的错误,所以我为您更正了它。

在此实例中,派生类使用 override (C# 关键字)标记方法。然后,我调用 base.Execute(MethodName, NoOfTimes);,因为我想在重写的实现中使用基类的实现。然后我输入了自己的代码。

base 是另一个关键字,它允许您访问紧邻您所在类的基类中的成员,而无需继承链将您推回派生成员。

abstract值得一读,但在这种情况下不是必需的(它与virtual的行为不同,但也与override结合使用)。

namespace Inheritance
{
    using System;
    public class Program
    {
        internal protected class BaseClass
        {
            public BaseClass() { }
            protected string methodName;
            protected int noOfTimes;
            public virtual void Execute(string MethodName, int NoOfTimes)
            {
                this.methodName = MethodName;
                this.noOfTimes = NoOfTimes;
            }
        }
        internal class DerivedClass : BaseClass
        {
            public DerivedClass() : base() { }
            public override void Execute(string MethodName, int NoOfTimes)
            {
                base.Execute(MethodName, NoOfTimes);
                Console.WriteLine("Running {0}, {1} times", base.methodName, base.noOfTimes);
            }
        }
        static void Main(string[] args)
        {
            DerivedClass d = new DerivedClass();
            d.Execute("Func", 2);
            Console.ReadLine();
        }
    }
}

此示例有一些代码格式和命名怪癖,但为了尽可能接近原始代码,我将不考虑这一点。

这将是模板方法模式的理想候选项。基类不是重写 Execute,而是调用必须由派生类提供的方法doWork。这样,您就不会忘记调用base.Execute并且可以在调用doWork之前和之后在基类中执行操作。

abstract class BaseClass 
{ 
    public BaseClass() { } 
    protected string methodName; 
    protected int noOfTimes; 
    public void Execute(string MethodName, int NoOfTimes) 
    { 
        this.methodName = MethodName; 
        this.noOfTimes = NoOfTimes;
        doWork();
    } 
    protected abstract void doWork(); // will be provided by derived classes
} 
class DerivedClass : BaseClass 
{ 
    public DerivedClass() : base() { } 
    protected override void doWork()
    {
        Console.WriteLine("Running {0}, {1} times", this.methodName, this.noOfTimes); 
    } 
} 
public class Program   
{   
    static void Main(string[] args) 
    { 
        DerivedClass d = new DerivedClass(); 
        d.Execute("Func", 2); 
        Console.ReadLine(); 
    } 
}

编辑:正如亚当在评论中正确指出的那样(谢谢),没有必要使基类抽象(如果你不需要实例化基类,这很方便,因为如果子类不提供doWork实现,它会产生编译时错误)。或者,您可以在基类中指定默认行为:

class BaseClass 
{ 
    public BaseClass() { } 
    protected string methodName; 
    protected int noOfTimes; 
    public void Execute(string MethodName, int NoOfTimes) 
    { 
        this.methodName = MethodName; 
        this.noOfTimes = NoOfTimes;
        doWork();
    } 
    protected virtual void doWork() {
        // default behaviour, can be modified by subclasses
    }
} 

此外,在这种情况下,不需要显式调用默认构造函数。

public DerivedClass() : base() { }

定义它就足够了

public DerivedClass() { }

基构造函数将在派生构造函数之前自动调用。

至于最初的问题,我同意亚当的观点,他只是更快地完成了他的回答。 :)

首先,在派生类中,您可以访问基类中定义为公共或受保护的所有方法、变量和属性。这意味着不需要在派生类中使用 base.methodName。

使用base(而不是通常隐式的this)来访问基类中定义的方法/属性的版本,而不是在派生类中重新定义。这里的情况并非如此。

此外,在您的情况下,您将在基类和派生类中使用不同的签名(即参数的不同数量和/或类型)定义 Execute。这意味着您必须单独调用它们,因为它们是不同的。

仅当您使用完全相同的参数在派生类中定义版本时,才能使用 Adam 指出的 virtual 和重写,即使该版本未使用它们也是如此。顺便说一句,这里您使用 base,因为您想调用基类中定义的 Execute 版本。