zoukankan      html  css  js  c++  java
  • 七、C# 接口

    并非只能通过继承使用多态性,还能通过接口使用它。
    和抽象类不同,接口不包含任何实现(方法)。
    然后和抽象类相似,接口也定义了一系列成员,调用者可以依赖这些成员来支持一个特定的功能。
     
    实现接口的类会使用与被实现的接口相同的签名来定义方法。
     
    通过基类来共享成员签名和实现,但通过接口只是共享成员签名,不共享实现。
     
    接口的一个关键特征就是它既不包含实现,也不包含数据。
    字段不能出现在一个接口中。
    但是可以使用属性,由于属性不会包含任何实现作为接口声明的一部分,所以它不会引用一个支持字段。
    C#不允许为接口成员使用访问修饰符。所有成员都自动定义为pulbic成员。
     
    一旦某个类声明自己要实现一个接口,则该接口的所有成员都必须实现。
    接口的一个重要特征在于,它们永远不能被实例化,不能使用new来创建一个接口。
    也正是这个原因,接口不能有构造器或终结器。接口实例只适用于实现它们的类型。
    除此之外,接口不能包含static成员。接口的一个重要目的就是实现多态性
     
    显式接口实现 ,隐式接口实现  
    在重写的方法和属性前是否添加接口名。
    1、显式成员实现
    在实现的方法和属性前加上接口名。
    由于显式接口实现直接与接口关联,因此没有必要使用virtual、override或者public来修饰它们。
     
    2、隐式成员实现
    不在实现的方法和属性前加上接口名。
    直接使用方法名和属性名
    隐式成员实现必须是public的,除此之外,virtual是可选的,具体取决于派生类是否可以重写实现。
    如果去掉virtual,该成员就如同是sealed成员。且override是不允许的。
    由于成员的接口声明不包含实现,所以override没有意义。
     
    3、显式接口实现与隐式接口实现的比较。
    显式接口实现是将“机制方面的考虑”与“模型方面的考虑”分隔开的一种技术。
    要求调用者先将对象转换为接口,然后才能认为对象是“可比较”的,可显式地区分你想在什么时候和模型 进行沟通,
    以及想在什么时候和实现机制打交道。
    以下一些基本的设计原则,可以利用它们来帮助自己选择显式还是隐式实现。
     成员是不是核心的类功能
    是:隐式
    否:显式
    接口成员名作为类成员是否恰当
    是:隐式
    否:显式
    是否已经有一个同名的类成员
    是:隐式
    否:显式
     1     class Program
     2     {
     3         static void Main(string[] args)
     4         {
     5  
     6             IListTable i;
     7             Contact c = new Contact();
     8             c.Name = "name1";
     9             Console.WriteLine(c.ColnumName);
    10  
    11             Appointment a = new Appointment();
    12             a.Name = "name2";
    13             Console.WriteLine(((IListTable)a).ColnumName);
    14  
    15             Console.ReadLine();
    16  
    17         }
    18     }
    19  
    20     interface IListTable
    21     {
    22         string ColnumName
    23         { get; }
    24     }
    25     public class Contact : IListTable
    26     {
    27         public string Name
    28         {
    29             get
    30             {
    31                 return FirtstName;
    32             }
    33             set
    34             {
    35                 FirtstName = value + " from Contact";
    36             }
    37         }
    38         private string FirtstName;
    39         //隐式实现
    40         public string ColnumName
    41         {
    42             get { return FirtstName + " ColnumName"; }
    43             set { FirtstName = value; }
    44         }
    45  
    46  
    47     }
    48     public class Appointment : IListTable
    49     {
    50         public string Name
    51         {
    52             get
    53             {
    54                 return FirtstName;
    55             }
    56             set
    57             {
    58                 FirtstName = value + " from Appointment";
    59             }
    60         }
    61         private string FirtstName;
    62  
    63         //显式实现
    64         string IListTable.ColnumName
    65         {
    66             get { return FirtstName + " ColnumName"; }
    67             //set { FirtstName = value; }//错误
    68         }
    69  
    70     }
     
     
    4、实现类与其接口之间的转型
    在实现类的实例中总是包含了接口中的全部成员,所以对象总是能成功转型为接口类型。
    从接口类型转为它的实现类,需要执行一次显式的转型。
     
    5、接口继承
    一个接口可以从另一个接口派生,派生的接口将继承“基接口”的所有成员。
     
    在用于显式接口成员实现的一个完全限定的接口成员名称中,必须引用最初声明它的那个接口的名称。
     
     
     1      class Program
     2     {
     3         static void Main(string[] args)
     4         {
     5  
     6  
     7         }
     8     }
     9  
    10     public interface IReadAbleSettingsProvider
    11     {
    12         string GetSetting(string name, string defaultValue);
    13     }
    14     public interface ISettingsProvider : IReadAbleSettingsProvider
    15     {
    16         void SetSetting(string name, string value);
    17     }
    18     class FileSettingsProvider : ISettingsProvider
    19     {
    20         public void SetSetting(string name, string value)
    21         {
    22             //
    23         }
    24         string IReadAbleSettingsProvider.GetSetting(string name, string defaultValue)
    25         {
    26             //
    27             return " ";
    28         }
    29     }
    30  
    即使类实现了从基接口派生的一个接口,类仍然可以公开声明两个接口的实现(两个接口都继承实现,放在限定符后面:)
     
     1     class FileSettingsProvider : ISettingsProvider, IReadAbleSettingsProvider
     2     {
     3         public void SetSetting(string name, string value)
     4         {
     5             //
     6         }
     7         string IReadAbleSettingsProvider.GetSetting(string name, string defaultValue)
     8         {
     9             //
    10             return " ";
    11         }
    12     }
     
    7、多接口继承
    就像类能实现多个接口那样,接口也可以从多个接口继承,而且语法与类的继承和实现的语法是一致的。
     
    8、接口上的扩展方法
    可以在别的类中为接口添加一个成员方法。(扩展方法必须在静态类中定义,且扩展方法需要static修饰)
     
    C#不仅允许为一个特定的对象实例添加扩展方法,还通话为那些对象的一个集合添加扩展方法。对扩展方法的支持是实现
    LINQ的基础 。
    IEnumerable是所有集合都要实现的基础接口。
    通过为IEnumberable定义扩展方法,为所有集合都添加了LINQ支持。
    这显著地改变了对象集合的编程方式。
     
     1     class Program
     2     {
     3         static void Main(string[] args)
     4         {
     5  
     6             Contact[] items = new Contact[] { new Contact(), new Contact() };
     7             for (int i = 0; i < items.Length; i++)
     8             {
     9                 items[i].ColnumName = "name" + i;
    10             }
    11             items.ListColumn();
    12  
    13  
    14  
    15             Console.ReadLine();
    16  
    17         }
    18     }
    19  
    20     interface IListTable
    21     {
    22         string ColnumName
    23         { get; }
    24     }
    25     public class Contact : IListTable
    26     {
    27         public string Name
    28         {
    29             get
    30             {
    31                 return FirtstName;
    32             }
    33             set
    34             {
    35                 FirtstName = value + " from Contact";
    36             }
    37         }
    38         private string FirtstName;
    39         //隐式实现
    40         public string ColnumName
    41         {
    42             get { return FirtstName + " ColnumName"; }
    43             set { FirtstName = value; }
    44         }
    45  
    46  
    47     }
    48    
    49     static class Listable
    50     {
    51         public static void ListColumn(this IListTable[] items)
    52         {
    53             string headers = "";
    54             for (int i = 0; i < items.Length; i++)
    55             {
    56                 headers += items[i].ColnumName + ",";
    57             }
    58             Console.WriteLine(headers);
    59         }
    60     }
    输出:
    name0 ColnumName,name1 ColnumName,
     
     
    8、通过接口实现多重继承
    虽然类只能从一个基类派生,但可以实现任意数量的接口,这有效解决了C#类不支持多重继承的问题。
    为此,我们要像上一章讲述的那样使用聚合,但可以稍微改变一下结构,在其中添加一个接口。
    需要写代码:
     1     public class PdaItem
     2     {
     3         public PdaItem()
     4         {
     5         }
     6         public PdaItem(DateTime pLastUpdated)
     7         {
     8  
     9             LastUpdated = pLastUpdated;
    10         }
    11         public DateTime LastUpdated { set; get; }
    12     }
    13     interface IPerson
    14     {
    15          string FirstName { set; get; }
    16          string LastName { set; get; }
    17     }
    18     public class Person : IPerson
    19     {
    20         public string Address { set; get; }
    21         public string Phone { set; get; }
    22  
    23         public string FirstName { set; get; }
    24         public string LastName { set; get; }
    25     }
    26     //使用聚合(实现继承Person 和 PdaItem 两个类,并将方法和属性放到接口当中
    27     public class Contact : PdaItem, IPerson
    28     {
    29         private Person _Person;
    30         public Person person
    31         {
    32             set
    33             {
    34                 _Person = value;
    35             }
    36             get
    37             {
    38                 return _Person;
    39             }
    40         }
    41         public string FirstName
    42         {
    43             get
    44             {
    45                 return _Person.FirstName;
    46             }
    47             set
    48             {
    49                 _Person.FirstName = value;
    50             }
    51         }
    52         public string LastName
    53         {
    54             get
    55             {
    56                 return _Person.LastName;
    57             }
    58             set
    59             {
    60                 _Person.LastName = value;
    61             }
    62         }
    63  
    64     }
        //IPerson 确保Person的成员和复制到Contact的成员具有一致的签名,然而,这个实现仍然没有作到"多重继承"真正同义
        //,因为添加到Person的新成员不会同时添加到Contact上(以上的是接口的实现没有带过来,也不能进行重写,只能利用继承这个接口,实现这个接口,重写那两个属性)。
        //如果被实现的成员是方法(不是属性),那么有一个办法可以对此进行改进。具体地说,就是为从第二个基类"派生"的附加功能定义接口扩展方法。
        //例如,IPerson上的一个扩展方法可以提供一个名为VerifyCredentials()的方法。这样一来,实现了IPerson的所有类(即使IPerson接口没有成员,只用扩展方法)
        //都会有VerifyCredentials()的一个默认实现。这之所以可行,完全是多态性和重写的功能。之所以支持重写,是因为一个方法的任何实例实现都要优先
        //具有相同静态签名的一个扩展方法。
    9、版本控制
    需要对程序增加功能时,不应该修改原来的接口,而是再定义一个接口,然后继承原来的接口,新接口上添加功能定义,
    再使需要增加功能的类实现该接口。
     
    10、接口与类的比较 
    接口引入 了另一个类别的数据类型(它们是少数不对终极基类System.Object进行扩展的类型之一,此外还有指针类型和类型参数类型)
     
    然后,和类不同的是,接口永远不能实例化。要访问一个接口p痊,只能通过对实现了接口的一个对象的引用来进行。
    不能为接口使用new运算。所以,接口不能包含任何构造器或终结器,除此之外,静态成员在接口上是不允许的。
     
    接口近似于抽象类,两者具有一些共同的特点。
     
     
     
     
     
  • 相关阅读:
    C# WPF开源控件库MaterialDesign介绍
    C# MQTT 服务端客户端通讯
    C#串口调试工具 (WPF/MVVM结构完整示例版)
    WPF转换器
    WPF动画基础及实例
    WPF MVVM架构 EF、WCF、IOC 设计示例经典
    SpringMVC中采用简洁的配置实现文件上传
    Maven 默认 SpringMVC-servlet.xml 基本配置
    maven pom.xml基本设置
    maven pom.xml设置jdk编译版本为1.8
  • 原文地址:https://www.cnblogs.com/tlxxm/p/4604528.html
Copyright © 2011-2022 走看看