從設計基類及其派生類看繼承關係

繼承可以定義可重用、擴展或修改父類行爲的子類。但基類的靜態構造函數、實例構造函數和析構函數不能被派生類繼承。ide

 在下面實例中,定義一個基類Publication用於表示任何類型的出版物以及派生至Publication的其餘類型Book類,由此也能夠擴展爲定義其餘類型如:Magazine、Journal、Newspaper和Article。函數

在設計基類Publication時咱們必須考慮到以下關係:ui

1.要在基類中添加哪些成員this

2.基類是否用做派生類模板的抽象基類spa

3.類層次結構的擴展空間大小,要開發包含三個或多個的類的層次結構,如Publication是Periodical的基類,又能夠是Magazine和Journal的基類設計

4.可否重寫基類實現的代碼,若是允許重寫,必須在基類中使用關鍵字virtual,派生類才能容許重寫基類方法。code

5.派生類是否必須繼承結構的終結類,且自己不被用做其餘派生類的基類,這時能夠用sealed 關鍵字來標識該類blog

先定義一個出版物類型的枚舉繼承

 public enum PublicationType:long
    {
        [Description("報紙")]
        Newspaper=1,
        [Description("雜誌")]
        Magazine =2,
        [Description("書籍")]
        Book=3
    }

再定義Publication抽象基類ip

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);
            }
        }

從輸出結果分析可得出:

一、Publication 和Book都隱式繼承自基類

二、派生類只能有一個一個直接基類,固然能夠隱式繼承object

三、繼承是能夠傳遞的。

參考文檔:https://docs.microsoft.com/zh-cn/dotnet/articles/csharp/tutorials/inheritance

相關文章
相關標籤/搜索