首页 > 代码库 > 从设计基类及其派生类看继承关系

从设计基类及其派生类看继承关系

继承能够定义可重用、扩展或修改父类行为的子类。但基类的静态构造函数、实例构造函数和析构函数不能被派生类继承。

 在下面实例中,定义一个基类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

 

从设计基类及其派生类看继承关系