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 次实现上述相同?
我希望我上面的例子很清楚。如果不是这样,请告诉我,我将提供更多详细信息。
谢谢
免责声明 ,我的回答假设您想要一个围绕方法继承及其实现的解决方案。提供的其他答案也是该问题的良好解决方案。
听起来您想重写派生类中的方法。为此,基类需要将方法标记为virtual
或abstract
。但是,在您的情况下,派生类方法签名是不同的。我将假设这是一个不了解它如何工作的错误,所以我为您更正了它。
在此实例中,派生类使用 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 版本。