博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
六、C# 派生
阅读量:7112 次
发布时间:2019-06-28

本文共 11676 字,大约阅读时间需要 38 分钟。

派生
对一个现有的类型进行扩展,以便添加更多的功能,或者对现有的类型的操作进行重写。
 
比如可以将两个类都适用的方法和属性,用一个新的类进行重构,两个类再分别继承这个类。
 
定义一个派生类时,要在类标识符后面添加一个冒号,接着添加基类名称。
 
可以多重继承,且继承链是没有限制的,每个派生类都拥有由其所有基类公开出来的全部成员。
 
注:所有的类都派生自object类。
 
1、基类型和派生类型之间的转型
由于派生建立了一个属于关系,所以总是可以将一个派生类型直接赋值给一个基类型。
 
隐式转换:可以将一个派生类的引用直接赋值给一个基类对象。不会发生数据丢失。
 
显式转换:语法格式与基本类型一致,有可能发生数据的丢失等。
 
隐式转型为基类不会实例化一个新的实例。相反,同一个实例会被引用为基类型,而它现在
提供的功能(也就是可访问的成员)是基类型的。
类似地,将基类向下转型为派生类,会引用更具体的类型,类型可用的操作也会进行扩展,但这
种转换是有限制的,实际被实例化的类型必须是要转换成的目标类型的一个实例。
注:从派生类转换为基类只会保留基类中可访问的成员,不能保留子类中可访问的成员。
代码:
  
1     class Program 2     { 3         static void Main(string[] args) 4         { 5             Contact contact = new Contact(); 6             PdaItem pda = new PdaItem(); 7             pda = contact; 8         } 9     }10     public class PdaItem11     {12         public string Name { set; get; }13         public DateTime LastUpdated { set; get; }14     }15     public class Contact : PdaItem16     {17         public string Address { set; get; }18         public string Phone { set; get; }19     }

 

2、定义自定义转换
类型间的转并不限于单一继承的类型。完全不相关的类型相互之间也能进行转换。这里的关键在于在两个
类型之间提供一个转型运算符。C#允许类型包含显式或隐式转型运算符。
implicit operator 类型(参数)
{
 
}
explicit operator 类型(参数)
{
 
}
代码:
1     class Program 2     { 3         static void Main(string[] args) 4         { 5             PdaItem pda = new PdaItem("name1", DateTime.Now); 6             Contact contact = new Contact("name2", DateTime.Now.AddDays(2), "beijing", "110"); 7             pda = contact; 8             Person person = new Person("PersonName1", "tianjin"); 9             contact = person;10         }11     }12     public class PdaItem13     {14         public PdaItem()15         {16         }17         public PdaItem(string pName, DateTime pLastUpdated)18         {19             Name = pName;20             LastUpdated = pLastUpdated;21         }22         public string Name { set; get; }23         public DateTime LastUpdated { set; get; }24     }25     public class Contact : PdaItem26     {27         public Contact()28         {29         }30         public Contact(string pName, DateTime pLastUpdated, string pAddress, string pPhone)31             : base(pName, pLastUpdated)32         {33             Address = pAddress;34             Phone = pPhone;35         }36         public string Address { set; get; }37         public string Phone { set; get; }38     }39     public class Person40     {41         public Person(string pName, string pAddress)42         {43             Name = pName;44             Address = pAddress;45         }46         public string Name { set; get; }47         public string Address { set; get; }48         /// 49         /// 隐式转换50         /// 51         /// 52         /// 
53 public static implicit operator Contact(Person person)54 {55 Contact c = new Contact();56 c.Name = person.Name;57 c.Address = person.Address;58 c.LastUpdated = DateTime.Today;59 c.Phone = "120";60 return c;61 }62 }

 

3、访问修饰符
在派生类当中可以访问 public、protected修饰的基类成员。
 
4、扩展方法
扩展方法的一个特点是,它们都是静态方法,不可被继承。
 
5、单一继承
C#是一种单一继承的编程语言,C#编译成的CIL语言也是一样。
在极少数需要多重继承结构的情况下,一般的解决方案是使用聚合,而不是继承第二个包含这个类的实例的类。
声明一个主要基类,然后派生一个出一个新的类。再定义第二个基类(只是名义上的),将第二个基类的一个对象作为派生类的一个字段,所有第二个基类的成员,都在派生类中重写。通过操作一个基类的对象实例来完成。
派生类将调用委托给字段。
除了因为委托而增加的复杂性,另一个缺点在于,在第二个基类上新增的任何方法
都需要人工添加到派生类中,否则派生类无法公共新增的功能(第二个基类上的功能需要操作第一个
基类中的成员和派生中的成员时)。
代码:
1     class Program 2     { 3         static void Main(string[] args) 4         { 5             Contact p = new Contact("xxm", DateTime.Now, 1); 6             Console.WriteLine(p.GetSex()); 7             Console.ReadLine(); 8   9  10         }11     }12     public class PdaItem13     {14         public PdaItem()15         {16         }17         public PdaItem(string pName, DateTime pLastUpdated)18         {19             Name = pName;20             LastUpdated = pLastUpdated;21         }22         public string Name { set; get; }23         public DateTime LastUpdated { set; get; }24     }25     public class Person26     {27         public Person(int pSex)28         {29             Sex = pSex;30         }31         public int Sex { set; get; }32         public string GetSex()33         {34             switch (Sex)35             {36                 case 0:37                     return "女";38                 case 1:39                     return "男";40                 default:41                     return "未定义";42             }43         }44  45  46     }47     public class Contact : PdaItem48     {49         public Contact()50         {51         }52         public Contact(string pName, DateTime pLastUpdated, int sex)53             : base(pName, pLastUpdated)54         {55             person = new Person(sex);56         }57         public Person person { set; get; }58         public int Sex59         {60             set { person.Sex = value; }61             get { return person.Sex; }62         }63         public string GetSex()64         {65             switch (Sex)66             {67                 case 0:68                     return Name + "," + "女" + "," + LastUpdated;69                 case 1:70                     return Name + "," + "男" + "," + LastUpdated; ;71                 default:72                     return Name + "," + "未定义" + "," + LastUpdated; ;73             }74         }75     }

 

6、密封类
把类标记为sealed修饰。
不能从密封类中派生出其他类,也就是不能作为基类被继承。
 
基类的重写
 
在派生类中可以访问基类的所有public、protected成员。
可以重写(替换)基类中的实现。
 
1、virtual修饰符
 
C#支持重写实例方法和属性,但不支持重写字段或者任何静态成员。
为了进行重写,要求在基类和派生类中都显式地执行一个操作。
在基类中,必须将允许重写的每个成员标记为virtual。
在派生类中使用override。
virtual标志着一个方法或属性可以在派生类中被替换(重写)。
 
重载一个成员,会造成“运行时”调用最底层的或者说派生得最远的实现。
 
虚方法只提供了默认实现,这种实现可由派生类完全重写。
注:只有实例成员才可以 是virtual的。static virtual是无意义的。也不允许出现。
1     class Program 2     { 3         static void Main(string[] args) 4         { 5             PdaItem p = new PdaItem("pname", DateTime.Now.AddDays(-2)); 6             Contact c = new Contact("name1", DateTime.Now); 7             p = c; 8             p.Name = "name1"; 9             Console.WriteLine(p.Name);10  11  12         }13     }14     public class PdaItem15     {16         public PdaItem()17         {18         }19         public PdaItem(string pName, DateTime pLastUpdated)20         {21             Name = pName;22             LastUpdated = pLastUpdated;23         }24         public virtual string Name { set; get; }25  26         public DateTime LastUpdated { set; get; }27     }28  29     public class Contact : PdaItem30     {31         public override string Name32         {33             get34             {35                 return FirtstName;36             }37             set38             {39                 FirtstName = value + " from Contact";40             }41         }42         public string FirtstName;43         public Contact()44         {45         }46         public Contact(string pName, DateTime pLastUpdated)47             : base(pName, pLastUpdated)48         {49  50  51         }52  53     }

 

输出:name1 from Contact;
2、new 运算符
 
在基类中的成员没有被声明为virtual时,如果在派生类中声明一个相同签名的成员时。
需要使用new修饰符(如果不指定override 和new,默认为new,从而维持了版本的安全性)。
使用new修饰符,它在基类面前隐藏了派生类的重新声明的成员。在这种情况下,不是调用派生得
最远的成员,相反,基类的成员会搜索继承链,找到使用了new修饰符的那个成员之前的成员,然后
调用该成员。如果继承链中仅包含两个类,就会使用基类的成员,感觉就像是派生类没有重写那个成
员。
注:以上针对的都是基类的对象的搜索。派生类对象的查找以其自身为标准,寻找自己的派生类中的重写之类的。
代码:
1     class Program 2     { 3         static void Main(string[] args) 4         { 5             PdaItem p = new PdaItem("pname", DateTime.Now.AddDays(-2)); 6             Contact c = new Contact("name1", DateTime.Now); 7             p = c; 8             p.Name = "name1"; 9             Console.WriteLine(p.Name);10  11  12         }13     }14     public class PdaItem15     {16         public PdaItem()17         {18         }19         public PdaItem(string pName, DateTime pLastUpdated)20         {21             Name = pName;22             LastUpdated = pLastUpdated;23         }24         public  string Name { set; get; }25  26         public DateTime LastUpdated { set; get; }27     }28  29     public class Contact : PdaItem30     {31         public new  string Name32         {33             get34             {35                 return FirtstName;36             }37             set38             {39                 FirtstName = value + " from Contact";40             }41         }42         public string FirtstName;43         public Contact()44         {45         }46         public Contact(string pName, DateTime pLastUpdated)47             : base(pName, pLastUpdated)48         {49  50  51         }52  53     }

 

输出:name1
3、sealed修饰符
virtual也可以通过sealed修饰符,从而禁止子类重写声明为virtual的基类成员。
在子类的使用了override重写的方法(任何用override修饰的成员会自动成为virtual成员,可以通过sealed修饰,防止被此类的子类继续重写。
 
4、base成员
重新声明一个成员时,开发者经常需要调用基类的一个成员。
通过base.成员,访问基类中的成员(通常用来访问被重写的成员)。
 
5、构造器
实例化一个派生类时,运行时 首先调用基类的构造器,以避免基类构造器被绕过。
假如基类没有默认构造器,就是需要在子类的构造器显式调用
public aaaa(string name):base(name)
{
 
}
6、抽象类
abstract 修饰。
抽象类是仅供派生的类。无法实例化一个抽象类,只能实例化从它派生的类。不抽象、可直接实例休的类称为具体类。
 
抽象类代表抽象的实体。其抽象成员定义了从抽象实例派生的一个对象应包含什么东西,但它们不能包含实现。
一个类要想从抽象类成功地派生,它必须为抽象基类中的抽象方法提供具体的实现。
抽象类的主要特征在于它包含抽象成员。抽象成员是不具有实现的一个方法或属性,其作用是强制所有派生类提供实现。
 
由于抽象成员应当是要被重写的,因此这类成员会自动成为virtual成员,而且不能这样显式地声明virtual。
抽象成员不能是private的,否则派生类看不见它们。
 
注:抽象类可以包含非抽象成员。
1     class Program 2     { 3         static void Main(string[] args) 4         { 5             PdaItem p; 6             Contact c = new Contact("contact name"); 7             p = c; 8             Console.WriteLine(p.Name +","+ p.GetSummary()); 9  10             Appointment ap = new Appointment("appointment name");11             p = ap;12             Console.WriteLine(p.Name + "," + p.GetSummary());13             Console.ReadLine();14  15  16         }17     }18     public abstract class PdaItem19     {20         public PdaItem()21         {22  23         }24         public PdaItem(string pName)25         {26             Name = pName;27         }28         public virtual string Name { set; get; }29         public abstract string GetSummary();30     }31  32     public class Contact : PdaItem33     {34         public new string Name35         {36             get37             {38                 return FirtstName;39             }40             set41             {42                 FirtstName = value + " from Contact";43             }44         }45         public string FirtstName;46         public Contact()47         {48         }49         public Contact(string pName)50             : base(pName)51         {52  53  54         }55         public override string GetSummary()56         {57             return "GetSummary() from Contact";58         }59  60     }61     public class Appointment : PdaItem62     {63         public new string Name64         {65             get66             {67                 return FirtstName;68             }69             set70             {71                 FirtstName = value + " from Appointment";72             }73         }74         public string FirtstName;75         public Appointment()76         {77         }78         public Appointment(string pName)79             : base(pName)80         {81  82  83         }84         public override string GetSummary()85         {86             return "GetSummary() from Appointment";87         }88  89     }

 

输出:
contact name,GetSummary() from Contact
appointment name,GetSummary() from Appointment
 
7、多态性
倘若同一个成员签名的实现在两个或多个类之间发生变化,就会获得面向对象程序设计的一个关键特性:多态性。
多态性(运行时多态)是指同一个签名可以有多个实现这一事实。
 
抽象成员是实现多态性的一个手段。(同理,虚成员也具有这一功效)。
代码:
8、所有类都从System.Object派生
 
System.Object的成员
Equals()
GetHashCode()
GetType()
ReferenceEquals()
ToString()
Finalize()
MemberwiseClose()
 
9、使用is运算符验证基础类型
对象 is 类型
is并非仅仅是检查数据能成功转型,还会检查底层对象本身是否是真的是一上对应的类型。
运算符能判断基础类型。
10、使用as运算符进行转换
对象   as  类型 
 
注:使用as运算符,在转换无效的前提下,会赋值null
 
is运算符相较于as运算符的一个优点在于,后者不能成功判断基础类型。后者允许在一个继承链上向上或向下转型为
支持转型运算符的类型。
 
 

转载于:https://www.cnblogs.com/tlxxm/p/4604526.html

你可能感兴趣的文章
Problems at works
查看>>
Dell服务器系统安装后无法正常进入系统
查看>>
深入理解asp.net里的HttpModule机制
查看>>
java基础学习_常用类03_StringBuffer类、数组高级和Arrays类、Integer类和Character类_day13总结...
查看>>
Asp.net MVC Session过期异常的处理
查看>>
python ThreadPoolExecutor线程池使用
查看>>
IPTABLES 规则(Rules)
查看>>
关于URL编码
查看>>
深度学习的可解释性研究(一):让模型「说人话」
查看>>
QT5提示can not find -lGL的解决方法
查看>>
Silverlight/Windows8/WPF/WP7/HTML5周学习导读(9月17日-9月23日)
查看>>
Tap-Ahead:让移动搜索更加便捷的解决之道
查看>>
Windows Server2016 Hyper-v Cluster部署
查看>>
juniper路由器配置
查看>>
jQuery一点一滴系列教程(第三点)
查看>>
ARP解决方法/工具 真假ARP防范区别方法 ARP终极解决方案
查看>>
系统数据权限的实现方案
查看>>
华为vlan划分,单臂路由以及静态路由
查看>>
UCD 2010百度工作坊
查看>>
ssh2免密码登录
查看>>