C#继承混淆

时间:2012-05-23 13:48:39

标签: c# inheritance

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

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次,我可以达到与上述相同的效果吗?

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

由于

4 个答案:

答案 0 :(得分:8)

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

听起来你想要覆盖派生类中的方法。为此,基类需要标记方法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();
        }
    }
}

此示例中有一些代码格式和命名怪癖,但我会单独留下以保持尽可能接近原始代码。

答案 1 :(得分:4)

这将是template method pattern的理想候选人。基类不是重写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(); 
    } 
}

编辑:正如Adam在评论中正确指出的那样(感谢),没有必要使基类抽象(如果你不需要实例化基类,那就很方便了) ,因为如果子类没有为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
    }
} 

答案 2 :(得分:1)

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

public DerivedClass() : base() { }

将其定义为

就足够了
public DerivedClass() { }

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

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

答案 3 :(得分:1)

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

使用

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

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

只有在派生类中使用完全相同的参数定义版本时,即使它们未被该版本使用,您也可以使用Adam指出的虚拟和覆盖。顺便说一句,这里你使用base,因为你想调用基类中定义的Execute版本。