如何使用接口和c#重写一个用抽象类编写的程序?
本文关键字:抽象类 一个 程序 接口 何使用 重写 | 更新日期: 2023-09-27 18:14:48
下面的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)
和not必须show de line:
--->bBase_methodX (NOT SHOW)
抽象类和接口不是一回事,所以你不可能有完全相同的行为。
接口只是一个契约,强制要求继承者必须拥有指定的方法和属性。接口不能有任何实现细节。
抽象类是不能被实例化的类,因此必须从它继承才能成为一个实际的对象。如果你想让基类中的函数不需要在子类中显式覆盖就能工作,那么你就不能使用接口。
最明显的例子就是构造函数。接口不定义方法的实现,所以如果不显式地编写控制台,从接口继承的东西将无法输出"Construc_dBase"行。在每个类的构造函数中使用WriteLine语句。使用您提供的代码,最接近的方法是创建以下接口:
public interface ISomeInterface
{
void methodX();
string s_dBase { get; set; }
}
. .然后在每个子类(不是基类)上继承该接口。
首先我将解释为什么,然后我将解释为什么它是不受欢迎的。
原因:
抽象方法在行为上与接口方法相同。它们定义了一个没有实现的签名,并且要求重写签名,否则程序将无法编译。你发布的代码中唯一符合模板的部分是methodX函数和string属性。因此,您可以将它们拉到一个接口中。但是,一旦这样做了,就必须在每个需要能够被解释为ISomeInterface的类上实现它们(即需要能够在不知道实现的情况下调用methodX)。继承基类上的接口意味着基类必须自己实际实现它们,这看起来是你不想做的。
为什么不受欢迎?
您现在不仅要继承基类,还要继承接口,以确保完全的互操作性。如果这对你来说不是太麻烦,那么你可以这么做,但这似乎是不必要的。此外,不再保证nmsD也是一个ISomeInterface,除非您在nmsD类上显式地提供methodX和s_dBase的实现,而这似乎正是您不想做的。此外,接口不定义可访问性约束(public、private、protectec、internal),而抽象类可以。
为什么有争议?
做事有不同的方法,每种方法都有其优点和缺点。抽象类将您束缚在单一的基实现上,而接口则不然。接口根本不能提供实现细节,而抽象类可以。这可能会进入一个非常偏离主题和非常冗长的讨论,所以我将在这里结束。
接口可以定义方法和属性签名,但没有实现。您可以将抽象类的签名更改为接口,将所有实现移动到继承的具体类。
抽象类和接口为两个不同的问题提供了解决方案,对于每个给定的场景,一个不可能和另一个一样好。如果你需要更多的帮助,请提供更多的信息。
下面是所提供的类的实现,使用接口和程序的输出。我尽量不弄乱类的命名。
输出: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( );
}
}
}