C#中的abstract、virtual、interface关键字
一、Virtual(虚方法修饰关键字)
virtual 关键字用于在基类中修饰方法。virtual的使用会有两种情况:
情况1:在基类中定义了virtual方法,但在派生类中没有重写该虚方法。那么在对派生类实例的调用中,该虚方法使用的是基类定义的方法。
情况2:在基类中定义了virtual方法,然后在派生类中使用override重写该方法。那么在对派生类实例的调用中,该虚方法使用的是派生重写的方法。
二、Abstract(抽象方法修饰关键字)
abstract关键字用在抽象类中修饰方法,并且没有具体的实现。抽象方法的实现必须在派生类中使用override关键字来实现,抽象类就是用来被继承的;可以看成是没有实现体的虚方法;如果类中包含抽象方法,那么类就必须定义为抽象类,不论是否还包含其他一般方法;
三、interface (接口修饰关键字)
区别:抽象类是一个不完全的类,是对对象的抽象,接口是一种行为规范。
示例:
namespace Community.BLL.Demo { /// <summary> /// 接口定义,接口只提供一些方法规约,不提供方法主体。方法不能用public abstract等修饰, 无字段变量,无构造函数。 /// </summary> public interface IPerson { void getName();//不包含方法主体 void getAge(string s);//方法可包含参数。 } /// <summary> /// 接口实现 /// </summary> public class Chinese : IPerson { public Chinese() { } //添加构造 public void getName() { } //实现getName() public void getAge(string s) { } //实现getAge() } /// <summary> /// 抽象类定义 /// abstract:声明抽象类、抽象方法 /// 1.抽象方法所在类必须为抽象类 /// 2.抽象类不能直接实例化,必须由其派生类实现。 /// 3.抽象方法不包含方法主体,必须由派生类以override方式实现此方法,这点跟interface中的方法类似 /// /// </summary> public abstract class BaseQuery { /// <summary> /// 构造函数 /// </summary> public BaseQuery() { } /// <summary> /// 抽象方法定义,不含主体,abstract关键字修饰方法,并且没有具体的实现。抽象方法的实现必须在派生类中使用override关键字来实现。 /// </summary> public abstract void Run(QueryRecord queryRecord); /// <summary> /// 一般方法,若在派生类中重写,须使用new关键字 /// </summary> public void StartQuery(QueryRecord queryRecord, dynamic queryParams) { var objA = new { queryParams.Name, queryParams.IdentifyNumber }; var objB = new { objA }; } /// <summary> /// 虚方法,可覆盖,不是必须的 /// </summary> public virtual void GetName() { } } /// <summary> /// 派生类定义001 /// </summary> public class Query001 : BaseQuery { /// <summary> /// 派生类中使用override关键字来实现基类中的抽象方法 /// </summary> public override void Run(QueryRecord queryRecord) { var queryParams = new { queryRecord.Name, queryRecord.IdentifyNumber }; //调用基类中的方法 base.StartQuery(queryRecord, queryParams); //没有重写该虚方法。那么在对派生类实例的调用中,该虚方法使用的是基类定义的方法。 base.GetName(); } /// <summary> /// 使用override重写该方法。那么在对派生类实例的调用中,该虚方法使用的是派生重写的方法。 /// </summary> public override void GetName() { } /// <summary> /// 一般方法,若在派生类中重写,须使用new关键字 /// </summary> new public void StartQuery(QueryRecord queryRecord, dynamic queryParams) { } } /// <summary> /// 派生类定义002 /// </summary> public class Query002 : BaseQuery { /// <summary> /// 派生类中使用override关键字来实现基类中的抽象方法 /// </summary> public override void Run(QueryRecord queryRecord) { var queryParams = new { queryRecord.Name, queryRecord.IdentifyNumber, Mobile = "138888888", CreateDate = DateTime.Now }; //调用基类中的方法 base.StartQuery(queryRecord, queryParams); } } /// <summary> /// 查询记录 /// </summary> public class QueryRecord { public string Name { get; set; } public string IdentifyNumber { get; set; } public string QueryType { get; set; } } /// <summary> /// 调用抽象方法 /// </summary> public class QueryBLL { /// <summary> /// 动态调用不同的类(Query001、Query002) /// </summary> public void RunQuery() { List<QueryRecord> list = new List<QueryRecord>(); list.Add(new QueryRecord() { Name = "张三", IdentifyNumber = "110111000000000001", QueryType = "Query001" }); list.Add(new QueryRecord() { Name = "李四", IdentifyNumber = "110111000000000002", QueryType = "Query002" }); foreach (QueryRecord queryRecord in list) { var queryType = queryRecord.QueryType; string assemblyName = this.GetType().Assembly.GetName().Name; var path = string.Format("{0}.{1},{2}", this.GetType().Namespace, queryType, assemblyName); BaseQuery obj = (BaseQuery)Activator.CreateInstance(Type.GetType(path)); obj.Run(queryRecord); } } } }
单元测试
#region 调用抽象类测试 [TestMethod] public void CallAbstractClassTest() { QueryBLL bll = new QueryBLL(); bll.RunQuery(); } #endregion