您的位置:首页 > 其它

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

2017-04-27 21:54 120 查看
继承能够定义可重用、扩展或修改父类行为的子类。但基类的静态构造函数、实例构造函数和析构函数不能被派生类继承。

在下面实例中,定义一个基类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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: