精通C#---接口

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/x13262608581/article/details/81161412

1.接口类型
接口是一组抽象成员的命名集合。

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 ICloneable
{
    object Clone();
}

class MyApp
{
    static void Main()
    {
        string mystr = "Hello";
        OperatingSystem unixOs = new OperatingSystem(PlatformID.Unix, new Version());
        System.Data.SqlClient.SqlConnection sqlCnn = new System.Data.SqlClient.SqlConnection();

        CloneMe(myStr);
        CloneMe(unixOs);
        CloneMe(sqlCnn);
    }

    private static void CloneMe(ICloneable c)
    {
        object theClone = c.Clone();// 将指向c的动态类型,对应版本的ICloneable::Clone
    }
}

2.定义自定义接口
接口不指定基类,接口可以指定基接口。
接口的成员也不指定访问修饰符【接口成员是隐式公共和抽象的】
接口是纯粹的协议,不会定义实现。
接口不能有字段,构造函数,不能提供函数实现。
接口中可以定义属性。也可以包含事件以及索引器。

接口本身仅仅是抽象成员的集合,只有被具体的类或结构实现时,才有其意义。

3.实现接口

public class Pencil : IPointy
{...}

public class SwitchBlade : object, IPointy
{...}

public class Fork : Utensil, IPointy
{...}

public struct Arrow : ICloneable, IPointy
{...}

实现接口是一个“要么全要要么全不要”的命题。

public interface IPointy
{
    byte Points{get;}
}

class Triangle : Shape, IPointy
{
    ...
    public byte Points
    {
        get{return 3;}
    }
}

class Hexagon : Shape, IPointy
{
    ...
    public byte Points
    {
        get{return 6;}
    }
}

4.在对象级别调用接口成员
如何动态判断一个类型支持哪些接口?
在运行时判断一个类型是否支持一个指定接口的方式
4.1.使用显式强制转换。如类型不支持被请求的接口,将收到一个无效转换异常【InvalidCastException】。
4.2.as

static void Main()
{
    Hexagon hex2 = new Hexagon("Peter");
    // 若Hexagon实现了IPointy,则返回转换后的IPointy
    // 若没实现,返回null
    IPointy itfPt2 = hex2 as IPointy;
    if(itfPts != null)
        ....    
}

4.3.is

static void Main()
{
    Hexagon hex2 = new Hexagon("Peter");
    // 若Hexagon实现了IPointy,则返回true
    // 若没实现,返回false
    if(hex2 is IPointy)
        // hex2.Points
}

5.接口做参数
接口可以做参数, 任何实现了此接口的类型实例,均可以作为实参传递。
在函数内,对接口对象执行成员调用时,将调用接口对象动态类型对应的实现版本。

6.接口作为返回值

static IPointy FindFirstPointyShape(Shape[] shapes)
{
    foreach(Shape s in shapes)
    {
        if(s is IPointy)
            return s as IPointy;
    }
    return null;
}

7.接口类型数组

static void Main()
{
    IPointy[] myPointObjects = 
    {
        new Hexagon(),
        new Knife(),
        new Triangle(),
        new Fork(),
        new PitchFork()
    };

    foreach(IPointy i in myPointyObjects)
    {
        Console.WriteLine("Object has {0} points", i.Points);
    }
}

8.显式接口实现
一个类或接口可以实现多个接口,多个接口可能包含同名且参数列表一致的成员。这时要处理冲突。

public interface IDrawToForm
{
    void Draw();
}

public interface IDrawToMemory
{
    void Draw();
}

public interface IDrawToPrinter
{
    void Draw();
}

class Octagon : IDrawToForm, IDrawToMemory, IDrawToPrinter
{
    // IDrawToForm, IDrawToMemory, IDrawToPrinter接口共享同一实现
    public void Draw()
    {
        Console.WriteLine("Drawing the Octagon...");
    }
}

class OctagonEx : IDrawToForm, IDrawToMemory, IDrawToPrinter
{
    // 提供独立实现。显式实现的成员是自动私有的,不允许指定访问修饰符。
    void IDrawToForm.Draw()
    {...}
    void IDrawToMemory.Draw()
    {...}
    void IDrawToPrinter.Draw()
    {...}
}

class MyApp
{
    OctagonEx oct = new OctagonEx();
    // 对于在类中提供接口显示实现的类型,接口中显示实现的成员是私有的。
    // 要通过此类型访问接口成员的唯一方式是,先把类类型强制转换为接口类型,然后在再执行接口成员访问。
    IDrawToForm itfForm = (IDrawToForm)oct;
    itfForm.Draw();
}

.NET基础类库中包含的许多预定义接口

1.IEnumerable,IEnumerator

public interface IEnumerable
{
    IEnumerator GetEnumerator();
}

public interface IEnumerator
{
    bool MoveNext();
    object Current{get;}
    void Reset();
}

使用示例:

using System.Collections;
public class Garage : IEnumerable
{
    private Car[] carArray = new Car[4];
    public Garage()
    {
        carArray[0] = new Car("FeeFee", 200, 0);
        carArray[1] = new Car("Clunker", 80, 0);
        carArray[2] = new Car("Zippy", 30, 0);
        carArray[3] = new Car("Fred", 30, 0);
    }

    public IEnumerator GetEnumerator()
    {
        return carArray.GetEnumerator();
    }
}

// 2,3 yield相关并不清楚
2.用yield关键字构建迭代器方法

public class Garage : IEnumerable
{
    private Car[] carArray = new Car[4];
    public IEnumerator GetEnumerator()
    {
        foreach(Car c in carArray)
        {
            // 达到yield return后,当前位置被存储下来。下次调用迭代器时会从这个位置开始执行
            yield return c;
        }
    }
}

3.构建命名迭代器

public IEnumerable GetTheCars(bool ReturnReversed)
{
    if(ReturnReversed)
    {
        for(int i = carArray.Length; i != 0; i--)
        {
            yield return carArray[i - 1];
        }
    }
    else
    {
        foreach(Car c in carArray)
        {
            yield return c;
        }
    }
}

static void Main()
{
    Garage carLot = new Garage();
    foreach(Car c in carLot)
    {
        Console.WriteLine("{0} is going {1} MPH", c.PetName, c.CurrentSpeed);
    }

    foreach(Car c in carLot.GetTheCars(true))
    {
        Console.WriteLine("{0} is going {1} MPH", c.PetName, c.CurrentSpeed);
    }

    Console.ReadLine();
}

2.ICloneable

public interface ICloneable
{
    object Clone();
}

public class Point
{
    public int X{get; set;}
    public int Y{get; set;}

    public Point(int xPos, int yPos)
    {
        X = xPos;
        Y = yPos;
    }
    public Point(){}

    public override string ToString()
    {
        return string.Format("X={0}; Y={1}", X, Y);
    }

    public object Clone()
    {
        return new Point(this.X, this.Y);
    }

    // 
    public object Clone()
    {
        // 重新在堆上分配一个类的对象,并对对象的成员变量逐个进行值拷贝。对引用类型成员变量,拷贝后新对象中引用和原对象中引用指向同一个堆上对象。
        return this.MemberwiseClone();
    }
}

static void Main(string[] args)
{
    Point p3 = new Point(100, 100);
    Point p4 = (Point)p3.Clone();
    // p4.X的改变不影响p3.X
    p4.X = 0;
}

更复杂的克隆示例

public class PointDescription
{
    public string PetName{get; set;}
    public Guid PointID{get; set;}
    public PointDescription()
    {
        PetName = "No-name";
        PointID = Guid.NewGuid();
    }
}

public class Point : ICloneable
{
    public int X{get; set;}
    public int Y{get; set;}
    public PointDescription desc = new PointDescription();
    public Point()
    {}

    public override string ToString()
    {
        return string.Format("X={0}, Y={1}, Name={2}, nID={3}\n", X,Y,desc.PetName, desc.PointID);
    }

    public object Clone()
    {
        // 分配对象,并逐个按值对对象成员进行复制。
        Point newPoint = (Point)this.MemberwiseClone();
        PointDescription currentDesc = new PointDescription();
        currentDesc.PetName = this.desc.PetName;
        newPoint.desc = currentDesc;
        return newPoint;
    }
}

3.IComparable

public interface IComparable
{
    int CompareTo(object o);
}

public class Car : IComparable
{
    ...
    // < 0,A < B
    // =,A = B
    // >, A > B
    int IComparable.CompareTo(object obj)
    {
        Car temp = obj as Car;
        if(temp != null)
        {
            if(this.CarID > temp.CarID)
                return 1;
            if(this.CarID < temp.CarID)
                return -1;
            else
                return 0;
        }
        else
            throw new ArgumentException("Parameter is not a Car!");
    }
}

4.IComparer

interface IComparer
{
    int Compare(object o1, object o2);
}

public class PetNameComparer : IComparer
{
    int IComparer.Compare(object o1, object o2)
    {
        Car t1 = o1 as Car;
        Car t2 = o2 as Car;
        if(t1 != null && t2 != null)
            return String.Compare(t1.PetName, t2.PetName);
        else
            throw new ArgumentException("Parameter is not a Car!");
    }
}

class MyApp
{
    public static void Main()
    {
        Car myAuto[10];
        ...
        Array.Sort(myAutos, new PetNameComparer());
    }
}

猜你喜欢

转载自blog.csdn.net/x13262608581/article/details/81161412