zoukankan      html  css  js  c++  java
  • 六、C# 派生

    派生
    对一个现有的类型进行扩展,以便添加更多的功能,或者对现有的类型的操作进行重写。
     
    比如可以将两个类都适用的方法和属性,用一个新的类进行重构,两个类再分别继承这个类。
     
    定义一个派生类时,要在类标识符后面添加一个冒号,接着添加基类名称。
     
    可以多重继承,且继承链是没有限制的,每个派生类都拥有由其所有基类公开出来的全部成员。
     
    注:所有的类都派生自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 PdaItem
    11     {
    12         public string Name { set; get; }
    13         public DateTime LastUpdated { set; get; }
    14     }
    15     public class Contact : PdaItem
    16     {
    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 PdaItem
    13     {
    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 : PdaItem
    26     {
    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 Person
    40     {
    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         /// <summary>
    49         /// 隐式转换
    50         /// </summary>
    51         /// <param name="person"></param>
    52         /// <returns></returns>
    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 PdaItem
    13     {
    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 Person
    26     {
    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 : PdaItem
    48     {
    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 Sex
    59         {
    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 PdaItem
    15     {
    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 : PdaItem
    30     {
    31         public override string Name
    32         {
    33             get
    34             {
    35                 return FirtstName;
    36             }
    37             set
    38             {
    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 PdaItem
    15     {
    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 : PdaItem
    30     {
    31         public new  string Name
    32         {
    33             get
    34             {
    35                 return FirtstName;
    36             }
    37             set
    38             {
    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 PdaItem
    19     {
    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 : PdaItem
    33     {
    34         public new string Name
    35         {
    36             get
    37             {
    38                 return FirtstName;
    39             }
    40             set
    41             {
    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 : PdaItem
    62     {
    63         public new string Name
    64         {
    65             get
    66             {
    67                 return FirtstName;
    68             }
    69             set
    70             {
    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运算符的一个优点在于,后者不能成功判断基础类型。后者允许在一个继承链上向上或向下转型为
    支持转型运算符的类型。
     
     
  • 相关阅读:
    PHP获取指定的时间戳
    Elasticsearch
    git有用基本指令
    php中的json_decode
    有用的sql积累
    git submodule使用原理
    mysql重复插入时insert更改为update更新操作
    jpm
    awk 语句
    tomcat 发布简单的html网站
  • 原文地址:https://www.cnblogs.com/tlxxm/p/4604526.html
Copyright © 2011-2022 走看看