• C#2008与.NET 3.5 高级程序设计读书笔记(9)接口


    1.接口定义

    接口的正式定义:接口就是一组抽象成员的结合.

    (1).一个接口定义了一个契约。
    (2).接口可以包容方法、C#属性、事件、以及索引器。
    (3).在一个接口声明中,我们可以声明零个或者多个成员。
    (4).所有接口成员的默认访问类型都是public。
    (5).如果在接口成员声明中包括了任何修饰符,那么会产生一个编译器错误。 

    正确接口代码例子:

    代码
    // IDbConnection接口定义了一组所有连接对象都支持的公共的成员。
    public interface IDbConnection : IDisposable
    {
    // 方法
    IDbTransaction BeginTransaction();
    IDbTransaction BeginTransaction(IsolationLevel il);
    void ChangeDatabase(string databaseName);
    void Close();
    IDbCommand CreateCommand();
    void Open();
    // 属性
    string ConnectionString { get; set;}
    int ConnectionTimeout { get; }
    string Database { get; }
    ConnectionState State {
    get; }
    }

    错误接口代码例子

    代码
    // 内有大量错误!
    public interface IPointy
    {
    // 错误!接口不能有字段!
    public int numbOfPoints;
    // 错误!接口不能有构造函数!
    public IPointy() { numbOfPoints = 0;};
    // 错误!接口不能提供实现!
    byte GetNumberOfPoints() { return numbOfPoints; }

    }

    2.对比接口类型和抽象基类

    虽然类类型定义了一组抽象成员,它完全可以再定义许多构造函数、字段数据、非抽象成员(具有实现)等。而接口,只能包含抽象成员。

    和抽象类的相似之处有三点:
    1、不能实例化;
    2、包含未实现的方法声明;
    3、派生类必须实现未实现的方法,抽象类是抽象方法,接口则是所有成员(不仅是方法包括其他成员);

    另外,接口有如下特性:
    接口除了可以包含方法之外,还可以包含属性、索引器、事件,而且这些成员都被定义为公有的。除此之外,不能包含任何其他的成员,例如:常量、域、构造函数、析构函数、静态成员。
    一个类可以直接继承多个接口,但只能直接继承一个类(包括抽象类)。

    由抽象父类创建的多态接口有一个主要的限制,那就是只有派生类型才支持由抽象父类定义的成员。然而,在大型软件系统中,开发除了System.Object之外没有公共父类的多个类层次结构很普遍。由于抽象基类中的抽象成员只应用到派生类型,我们就不能以多个层次结构配置类型来支持相同的多态接口。

    3.获取接口引用is和as关键字

    代码
    //生成Shape类型的数组,使其中部分成员实现了IPointy接口。
    Shape[] s = { new Hexagon(), new Circle(), new Triangle("Joe"),
    new Circle("JoJo")} ;
    for(int i = 0; i < s.Length; i++)
    {
    // 哪些是有棱角的?
    if(s[i] is IPointy)
    Console.WriteLine(
    "-> Points: {0}", ((IPointy)s[i]).Points);
    else
    Console.WriteLine(
    "-> {0}\'s not pointy!", s[i].PetName);
    Console.WriteLine();
    }
    代码
    // 我们能将六角形hex2视为实现了IPointy接口吗?
    Hexagon hex2 = new Hexagon("Peter");
    IPointy itfPt2
    = hex2 as IPointy;
    if(itfPt2 != null)
    Console.WriteLine(
    "Points: {0}", itfPt2.Points);
    else
    Console.WriteLine(
    "OOPS! Not pointy...");
    4.接口的常用使用方法:

    (1).接口作为参数
    代码
    static void DrawIn3D(IDraw3D itf3d)
    {
    itf3d.Draw3D();
    }
    //调用代码
    Shape[] s = { new Hexagon(), new Circle(),
    new Triangle(), new Circle("JoJo") } ;
    for(int i = 0; i < s.Length; i++)
    {
    // 支持绘制为3D吗?
    if(s[i] is IDraw3D)
    DrawIn3D((IDraw3D)s[i]);
    }

    (2).接口作为返回值

    代码
    // 这个方法检查对象是否支持IPointy接口,
    // 如果是,返回一个接口引用。
    static IPointy ExtractPointyness(object o)
    {
    if (o is IPointy)
    return (IPointy)o;
    else
    return null;
    }
    //调用方法
    // 试图从ints对象获取IPointy接口。
    int[] myInts = {10, 20, 30};
    IPointy itfPt
    = ExtractPointyness(myInts);
    if(itfPt != null)
    Console.WriteLine(
    "Object has {0} points.", itfPt.Points);
    else
    Console.WriteLine(
    "This object does not implement IPointy");

    (3).接口类型数组

     同样的接口即使不在同一个类层次结构,也没有除System.Object以外的公共父类,也可以由多个类型实现,这可以派生出许多非常强大的编程构造。

    代码
    // 这个数组仅仅包含实现了IPointy接口的类型。
    IPointy[] myPointyObjects = {new Hexagon(), new Knife(),
    new Triangle(), new Fork(), new PitchFork()};
    foreach(IPointy i in myPointyObjects)
    Console.WriteLine(
    "Object has {0} points.", i.Points);

    5.IEnumerable 和 IEnumerator 接口

    IEnumerable:

    IEnumerator GetEnumerator() 返回可循环访问集合的枚举数。

    公开枚举数,该枚举数支持在非泛型集合上进行简单迭代。

    该接口只定义了一个函数:GetEnumerator,通过该函数返回一个循环访问集合的枚举数。

    若要支持foreach语义则须实现此接口。

    IEnumerator:

    object Current 获取集合中的当前元素。
    bool MoveNext() 将枚举数推进到集合的下一个元素。
    如果枚举数成功地推进到下一个元素,则为 true;如果枚举数越过集合的结尾,则为 false
    void Reset() 将枚举数设置为其初始位置,该位置位于集合中第一个元素之前。

    IEnumerator 是所有非泛型枚举数的基接口。C# 语言的 foreach 语句(在 Visual Basic 中为 for each)隐藏了枚举数的复杂性。因此,建议使用 foreach,而不直接操作枚举数。

    MSDN例子:

    代码
    using System;
    using System.Collections;

    public class Person
    {
    public Person(string fName, string lName)
    {
    this.firstName = fName;
    this.lastName = lName;
    }

    public string firstName;
    public string lastName;
    }

    public class People : IEnumerable
    {
    private Person[] _people;
    public People(Person[] pArray)
    {
    _people
    = new Person[pArray.Length];

    for (int i = 0; i < pArray.Length; i++)
    {
    _people[i]
    = pArray[i];
    }
    }

    public IEnumerator GetEnumerator()
    {
    return new PeopleEnum(_people);
    }
    }

    public class PeopleEnum : IEnumerator
    {
    public Person[] _people;

    // Enumerators are positioned before the first element
    // until the first MoveNext() call.
    int position = -1;

    public PeopleEnum(Person[] list)
    {
    _people
    = list;
    }

    public bool MoveNext()
    {
    position
    ++;
    return (position < _people.Length);
    }

    public void Reset()
    {
    position
    = -1;
    }

    public object Current
    {
    get
    {
    try
    {
    return _people[position];
    }
    catch (IndexOutOfRangeException)
    {
    throw new InvalidOperationException();
    }
    }
    }
    }

    class App
    {
    static void Main()
    {
    Person[] peopleArray
    = new Person[3]
    {
    new Person("John", "Smith"),
    new Person("Jim", "Johnson"),
    new Person("Sue", "Rabon"),
    };

    People peopleList
    = new People(peopleArray);
    foreach (Person p in peopleList)
    Console.WriteLine(p.firstName
    + " " + p.lastName);

    }
    }

    /* This code produces output similar to the following:
    *
    * John Smith
    * Jim Johnson
    * Sue Rabon
    *
    */

    教材上的例子:

    代码
    using System;
    using System.Collections
    public class Garage : IEnumerable
    {
    // System.Array已经实现了IEnumerator!
    private Car[] carArray = new Car[4];
    public Garage()
    {
    carArray[
    0] = new Car("FeeFee", 200,0);
    carArray[
    1] = new Car("Clunker", 90, 0);
    carArray[
    2] = new Car("Zippy",30,0);
    carArray[
    3] = new car("Fred",30,0);
    }
    public IEnumerator GetEnumerator()
    {
    // 返回数组对象的IEnumerator。
    return carArray.GetEnumerator();
    }
    }

    6.IComparable接口

    IComparable接口用来支持在集合中排序。它有一个函数——CompareTo。当你设计分类对象时,你必须实现IComparable的CompareTo方法。

    比如,我做一个Developer类来继承IComparable。

    public class Developer : IComparable
    {
    }

    现在我来实现ComparaTo方法如下:

    public int CompareTo(object obj)
    {
    // Some code here
    }

    现在我们说,Developer类有一个属性叫ID,而你希望你的这些项目按照ID来排序,我们简单的加入如下代码:

    代码
    public int CompareTo(object obj)

    {

    if( !(obj is Developer) )

    throw new InvalidCastException("Not a valid Developer object.");

    Developer developer
    = (Developer)obj;

    return this.ID.CompareTo(developer.ID);
    //使用IComparable为他们排序
    //Array.Sort();

    }
  • 相关阅读:
    leetCode21. 合并两个有序链表
    (flag)每日三道面试题(4.25)
    每日三加一面试题(4.21)
    按照顺序执行异步函数
    javascript Proxy 代理模式深度监听对象、数组变化
    数据结构与算法(二) 线性表一
    This关键字
    数据结构与算法(一)
    Git报错信息
    MakeDown语法学习
  • 原文地址:https://www.cnblogs.com/engine1984/p/1771355.html
Copyright © 2020-2023  润新知