【问题标题】:How can I rewrite a program that was written with abstract class using interface and C#?如何重写使用接口和 C# 用抽象类编写的程序?
【发布时间】:2014-09-17 23:18:39
【问题描述】:

以下 C# 程序是使用抽象类编写的:

dBase.cs

using System;
namespace nmsD
{
    public abstract class dBase
    {
        protected string s_dBase { get; set; }
        protected abstract void methodX();
        public dBase()
        {
            Console.WriteLine("Construc_dBase");
        }
        public void Dq1 ()
        {
            string s = s_dBase;
            Console.WriteLine("Dq1" + " : " + s);
            methodX();
        }
    }
}

bBase.cs

using System;
using nmsD;
namespace nmsB 
{
    public abstract class bBase: dBase
    {

        public bBase()
        {
            s_dBase = "Prop.bBase.01";
            Console.WriteLine("Construc_bBase");
        }

        protected override void methodX(){
            Console.WriteLine("--->bBase_methodX (NOT SHOW)");
        }
    }

}

bRegular01

using System;
using nmsD;

namespace nmsB 
{
    public class bRegular01 : bBase
    {
        public bRegular01()
        {
            Console.WriteLine("Construc_bRegular01");
            //s_dBase = "Prop.bRegular02.02";
        }
        protected override void methodX()
        {
            Console.WriteLine("--->bRegular01_methodX (OK)");
        }
    }
}

bRegular02

using System;
using nmsD;

namespace nmsB 
{
    public class bRegular02 : bBase
    {
        public bRegular02()
        {
            Console.WriteLine("Construc_bRegular02");
            s_dBase = "Prop.bRegular02.02";
        }

        protected override void methodX()
        {
            Console.WriteLine("--->bRegular02_methodX (OK)");
        }
    }
}

Program.cs

using System;
using nmsB;

namespace nmsApp
{
    class Program
    {
        static void Main(string[] args)
        {
            nmsB.bRegular01 br01 = new nmsB.bRegular01();
            br01.Dq1();

            nmsB.bRegular02 br02 = new nmsB.bRegular02();
            br02.Dq1();

            Console.ReadKey();
        }
    }
}

输出为:

    Construc_dBase
    Construc_bBase
    Construc_bRegular01
    Dq1 : Prop.bBase.01
    --->bRegular01_methodX (OK)
    Construc_dBase
    Construc_bBase
    Construc_bRegular02
    Dq1 : Prop.bRegular02.02
    --->bRegular02_methodX (OK)

问题是:

如果可能,如何使用接口执行相同的行为? 获得此结果的最佳方法是什么?为什么?

编辑:

非常感谢您的回答。基于第一个答案,为了更好地理解,主要目标是: 当从 Dq1 调用方法 methodX() 时。输出必须只显示以下行:

--->bRegular01_methodX (OK)
or
--->bRegular02_methodX (OK)

不一定要显示分界线:

--->bBase_methodX (NOT SHOW)

【问题讨论】:

    标签: c# oop interface abstract


    【解决方案1】:

    抽象类和接口不是一回事,所以你不能有完全相同的行为。

    接口只是强制继承者必须具有规定的方法和属性的契约。接口不能有任何实现细节。

    抽象类是无法实例化的类,因此必须从其继承才能生成实际对象。如果您希望基类中的函数不必在子类中显式重写,那么您不能使用接口。

    最明显的例子就是你的构造函数。接口不定义方法的实现,因此从接口继承的东西将无法输出您的“Construc_dBase”行,除非在每个类的构造函数中显式编写 Console.WriteLine 语句。

    使用您提供的代码,您可以获得的最接近的方法是创建以下接口:

    public interface ISomeInterface
    {
        void methodX();
        string s_dBase { get; set; }
    }
    

    ..然后在您的每个子类(不是基类)上继承该接口。

    首先我会解释为什么,然后我会解释为什么它是不可取的。

    为什么:

    抽象方法在行为上与接口方法相同。他们定义了一个没有实现的签名,并要求它们被覆盖,否则程序将无法编译。您发布的代码中唯一符合该模板的部分是 methodX 函数和 string 属性。因此,您可以将它们拉出到界面中。但是,一旦这样做,您将不得不在每个需要能够被解释为 ISomeInterface 的类上实现它们(即需要能够在不知道实现的情况下调用 methodX)。继承基类上的接口意味着基类必须自己实际实现它们,这看起来是你不想做的。

    为什么不受欢迎?

    您现在不仅要负责继承基类,还要负责接口,以确保完全的互操作性。如果这对您来说不是太繁重,那么一定要这样做,但这似乎没有必要。此外,不再保证 nmsD 也是 ISomeInterface,除非您在 nmsD 类上明确提供 methodX 和 s_dBase 的实现,这似乎正是您不想做的事情。此外,接口不定义可访问性约束(公共、私有、protectec、内部),而抽象类可以。

    为什么有争议?

    有不同的做事方式,每一种都有其优点和缺点。抽象类将您绑定到单个基本实现,而接口则没有。接口根本无法提供实现细节,而抽象类可以。

    不过,这可能会成为一个非常偏离主题且非常冗长的讨论,所以我将在此停止。

    【讨论】:

    • 你把他的问题说得比我做得更好+1
    • 我实际上推荐接口 - [几乎] 总是,即使是抽象类。抽象类有助于实现,而接口可以(并且应该)用于合同。
    • 想详细说明该评论吗?我总是乐于听取好主意。 :)
    • 非常感谢您的回答,主要目的是:当从Dq1调用方法methodX()时。输出必须仅显示带有以下内容的行:--->bRegular01_methodX (OK) 或 --->bRegular02_methodX (OK),而不必须显示 de line: --->bBase_methodX (NOT SHOW)
    • 这个示例程序是我需要改进和修复的现有项目的几个类的恢复版本。所有类都使用相同的模式。但问题是没有抽象类或任何接口类,而且有很多重复的代码。所有代码子集看起来都像(dBase、bBase 和 Regular01)对于许多其他方法都重复多次相同的代码:(dBase、bBase 和 Regular 01)、(dBase、dBase 和 Regular 02)...(dBase , dBase 和 Regular0n)。
    【解决方案2】:

    接口可以定义方法和属性签名,但没有实现。您可以将抽象类的签名更改为接口,将所有实现移至继承的具体类。

    抽象类和接口为两个不同的问题提供了解决方案,在每个给定的场景中,一个不会和另一个一样好。如果您需要更多帮助,请提供更多信息。

    【讨论】:

    • 感谢您的回答。我编辑了这个问题并在其他答案中发布了一些 cmets。如果您能再次发表您的意见,我将不胜感激。
    【解决方案3】:

    这是所提供的类的实现,使用接口和程序的输出。我尽量不要弄乱类的命名。

    输出:

    Construc_bRegular01
    Dq1: Prop.bRegular01.01
    --->bRegular01_methodX (OK)
    Construc_bRegular02
    Dq1: Prop.bRegular02.02
    --->bRegular02_methodX (OK)
    

    代码:

    namespace nmsD
    {
        public interface IdBase
        {
            string s_dBase { get; set; }
            void methodX( );
            void Dq1( );
        }
    
    }
    
    namespace nmsB
    {
        using nmsD;
    
        public class bRegular01 : IdBase
        {
            public bRegular01( )
            {
                Console.WriteLine( "Construc_bRegular01" );
                s_dBase = "Prop.bRegular01.01";
            }
    
            public string s_dBase { get; set; }
    
            public void methodX( )
            {
                Console.WriteLine( "--->bRegular01_methodX (OK)" );
            }
    
            public void Dq1( )
            {
                Console.WriteLine( "Dq1: {0}", s_dBase );
                methodX( );
            }
        }
    
        public class bRegular02 : IdBase
        {
            public bRegular02( )
            {
                Console.WriteLine( "Construc_bRegular02" );
                s_dBase = "Prop.bRegular02.02";
            }
    
            public string s_dBase { get; set; }
    
            public void methodX( )
            {
                Console.WriteLine( "--->bRegular02_methodX (OK)" );
            }
    
            public void Dq1( )
            {
                Console.WriteLine( "Dq1: {0}", s_dBase );
                methodX( );
            }
        }
    }
    
    
    namespace nmsApp
    {
        internal class Program
        {
            private static void Main( string[ ] args )
            {
                nmsB.bRegular01 br01 = new nmsB.bRegular01( );
                br01.Dq1( );
    
                nmsB.bRegular02 br02 = new nmsB.bRegular02( );
                br02.Dq1( );
    
                Console.ReadKey( );
            }
        }
    }
    

    【讨论】:

    • 感谢您的回答@dodexahedron。
    • 这几乎是我想要实现的。如果(我不知道如何),尽管我之前在编辑的问题中没有问过这个问题,如果它存在一个带有构造函数(运行方法或语句)的中间类来显示相应的,那将是完美的到我在问题正文中发布的行:“Construc_bBase”。因为,这个程序是一个真实的和更大的项目的简单简介或简历。但是您的回答对我理解接口在 C# 中的工作方式有很大帮助。非常感谢。
    • 那么你肯定需要一个其他类需要继承的类(无论是否抽象)。接口不具备这种行为。如果你想共享代码/实现,你必须使用一个类。很高兴我为你提供了一些启示。祝项目好运。
    • 嗯,我改变主意了。对不起,但是,我分析了你的代码,有两个对 methodX() 的调用。一个在 bRegular01 中,另一个在 bRegular02 中。正确的应该是,在对 bRegular01 和 bRegular02 的基类中对该方法 X 的唯一调用。输出是我所期待的。但这不是预期的行为。但再次感谢您。
    • 我写的时候,你在我面前发表你的评论。你的代码对我帮助很大。我将在这个示例中工作,以尝试获得预期的结果。
    猜你喜欢
    • 2014-08-21
    • 2017-02-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多