首页 > 代码库 > 从设计基类及其派生类看继承关系
从设计基类及其派生类看继承关系
继承能够定义可重用、扩展或修改父类行为的子类。但基类的静态构造函数、实例构造函数和析构函数不能被派生类继承。
在下面实例中,定义一个基类Publication用于表示任何类型的出版物以及派生至Publication的其他类型Book类,由此也可以扩展为定义其他类型如:Magazine、Journal、Newspaper和Article。
在设计基类Publication时我们必须考虑到如下关系:
1.要在基类中添加哪些成员
2.基类是否用作派生类模板的抽象基类
3.类层次结构的扩展空间大小,要开发包含三个或多个的类的层次结构,如Publication是Periodical的基类,又可以是Magazine和Journal的基类
4.能否重写基类实现的代码,如果容许重写,必须在基类中使用关键字virtual,派生类才能允许重写基类方法。
5.派生类是否必须继承结构的终结类,且本身不被用作其他派生类的基类,这时可以用sealed 关键字来标识该类
先定义一个出版物类型的枚举
public enum PublicationType:long { [Description("报纸")] Newspaper=1, [Description("杂志")] Magazine =2, [Description("书籍")] Book=3 }
再定义Publication抽象基类
public abstract class Publication { private bool published = false; private DateTime datePublished; private int totalPages; public Publication(string title,string publisher,PublicationType type) { if (string.IsNullOrWhiteSpace(title)) throw new ArgumentNullException("title can not be null or white space"); Title = title; if (string.IsNullOrWhiteSpace(publisher)) throw new ArgumentNullException("publisher can not be null or white space"); Publisher = publisher; Type = type; } public string Publisher { get; } public string Title { get; } public PublicationType Type { get; } public string CopyrightName { get; private set; } public int CopyrightDate { get; private set; } public int Pages { get { return totalPages; } set { if (value < 0) throw new ArgumentOutOfRangeException("The number of pages cannot be zero or negative"); totalPages = value; } } public string GetPublicationDate() { if (!published) return "NYP"; else return datePublished.ToString("d"); } public void Publish(DateTime datePublished) { published = true; this.datePublished = datePublished; } /// <summary> /// 定义所有权名称和期限 /// </summary> /// <param name="copyrightName"></param> /// <param name="copyrightDate"></param> ///<remarks></remarks> public void Copyright(string copyrightName,int copyrightDate) { if (string.IsNullOrEmpty(copyrightName)) throw new ArgumentNullException("The copyright name can not be null or empty"); CopyrightName = copyrightName; var currentYear = DateTime.Now.Year; if (copyrightDate < currentYear - 10 || copyrightDate > currentYear + 2) throw new ArgumentOutOfRangeException($"the copyright year must be validate"); CopyrightDate = copyrightDate; } public override string ToString() => Title; }
Book表示一种类型的出版物,继承至Publication
public sealed class Book:Publication { public Book(string title,string guid,string author, string publisher) : base(title, publisher, PublicationType.Book) { if (string.IsNullOrEmpty(guid)) throw new ArgumentNullException("GUID can not be null or empty"); GUID = guid; Author = author; } public string GUID { get; } public string Author { get; } public decimal Price { get; private set; } public string Currency { get; private set; } /// <summary> /// 设置新的价格返回旧价格 /// </summary> /// <param name="price"></param> /// <param name="currency"></param> /// <remarks></remarks> /// <returns>旧价格</returns> public decimal SetPrice(decimal price, string currency) { if (price < 0) throw new ArgumentOutOfRangeException("price can not be negative"); var oldPrice = Price; Price = price; if (currency.Length != 3) throw new ArgumentNullException("the currency is a 3-character string"); Currency = currency; return oldPrice; } public override bool Equals(object obj) { var book = obj as Book; return book == null ? false : GUID.Equals(book.GUID); } public override int GetHashCode() => GUID.GetHashCode(); public override string ToString() => $"{(string.IsNullOrEmpty(Author) ? "" : Author + ",")}{Title}"; }
在代码图中查看Book和Publication类的依赖关系和类中成员的引用关系
使用反射分别获取Book和Publication类的成员列表
class Program { static void Main(string[] args) { var tPublication = typeof(Publication); var tBook = typeof(Book); var flags = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy; var membersPublication = tPublication.GetMembers(flags); var membersBook = tBook.GetMembers(flags); OutputClassInfo(tPublication, membersPublication); OutputClassInfo(tBook, membersBook); Console.ReadKey(); } private static void OutputClassInfo(Type t, MemberInfo[] members) { Console.WriteLine($"Type {t.Name} has {members.Length} members:"); foreach (var member in members) { var access = string.Empty; var stat = string.Empty; if (member is MethodBase method) { if (method.IsPublic) access = "Public"; else if (method.IsPrivate) access = "Private"; else if (method.IsFamily) access = "Protected"; else if (method.IsAssembly) access = "Internal"; else if (method.IsFamilyOrAssembly) access = "Protected Internal"; if (method.IsStatic) stat = "Static"; } var output = $"{member.Name} ({member.MemberType}): {access}{stat}, Declared by {member.DeclaringType}"; Console.WriteLine(output); } }
从输出结果分析可得出:
1、Publication 和Book都隐式继承自基类
2、派生类只能有一个一个直接基类,当然可以隐式继承object
3、继承是可以传递的。
参考文档:https://docs.microsoft.com/zh-cn/dotnet/articles/csharp/tutorials/inheritance
从设计基类及其派生类看继承关系