《CLR Via C# 第3版》笔记之(十五) – 接口

3. 泛型接口和封锁

泛型是往日看过的概念,在接口中行使泛型,同样可以收获泛型带给我们的各类好处。

  1. 提供项目安全性

譬如说IComparable接口和IComparable<Int32>接口比较,后者提供了体系安全检查。

        int x = 1;
        IComparable c1 = x;
        // 编译通过,但是运行时异常
        c1.CompareTo("2");

        IComparable<Int32> c2 = x;
        // 编译不通过,类型不匹配
        c2.CompareTo("2");
  1. 减掉装箱次数

或者用IComparable接口和IComparable<Int32>接口做比较。

        int x = 1, y = 2;
        // 此处装箱一次 (x装箱)
        IComparable c1 = x;
        // 此处装箱一次 (y装箱)
        c1.CompareTo(y);

        // 此处装箱一次 (x装箱)
        IComparable<Int32> c2 = x;
        // 此处不用装箱,因为类型参数T为Int32
        c2.CompareTo(y);
  1. 一个类可以完结同泛型参数类型不一样的同一个接口,如下所示

    class MyClass : IComparable,IComparable
    {

     #region IComparable<int> Members
    
     public int CompareTo(int other)
     {
         throw new NotImplementedException();
     }
    
     #endregion
    
     #region IComparable<string> Members
    
     public int CompareTo(string other)
     {
         throw new NotImplementedException();
     }
    
     #endregion
    

    }

接口(interface)和类(class)是CLR中使用最为普遍的七个概念。灵活的应用接口,可以社团出种种经典的设计方式。

接口的语法并不复杂,本篇首要记录接口中有的便于忽略的地点,以及怎么着更好的使用接口。

1. 接口的存续

当子类继承父类后,父类继承的接口也一并一连了过来。如下例中的类Sub

当子类继承父类后,子类可以重复无冕父类已经持续的接口。如下例中的类Sub2

那二者的分别在对接口方法调用,参见上面代码中的注释。

using System;

sealed class CLRviaCSharp_15
{
    static void Main(string[] args)
    {
        Sub s = new Sub();
        // 类Sub自身的Show方法
        s.Show();
        // 类Base的Show方法,即继承自IShowMessage的Show方法
        ((Base)s).Show();
        // 类Base继承自IShowMessage的Show方法
        ((IShowMessage)s).Show();
        Console.WriteLine("=============================");
        Sub2 s2 = new Sub2();
        // 类Sub2自身的Show方法,即继承自IShowMessage的Show方法
        s2.Show();
        // 类Base的Show方法
        ((Base)s2).Show();
        // 类Sub2继承自IShowMessage的Show方法
        ((IShowMessage)s2).Show();

        Console.ReadKey();
    }
}

interface IShowMessage
{
    void Show();
}

class Base : IShowMessage
{
    public void Show()
    {
        Console.WriteLine("IShowMessage");
    }
}


/// <summary>
/// 当子类继承父类后,父类继承的接口也一并继承了过来
/// </summary>
class Sub : Base
{
    // 类Sub本身的Show方法,与Base中继承IShowMessage的Show无关
    public new void Show()
    {
        Console.WriteLine("Sub");
    }
}

/// <summary>
/// 子类继承父类后,子类可以再次继承父类已经继承的接口
/// </summary>
class Sub2 : Base, IShowMessage
{
    // 类Sub2继承IShowMessage的Show方法,
    // 与Base中继承IShowMessage的Show无关
    public new void Show()
    {
        Console.WriteLine("Sub2");
    }
}  

2. 显式接口

在上例中,类Base继承IShowMessage之后,就无法定义与
IShowMessage中签名相同的章程了。

如上例中,类Base无法再定义与情势Show相同签名的办法了。

为驾驭决那种景色,C#中还提供了显式接口的定义方法。

class Base : IShowMessage
{
    public void Show()
    {
        Console.WriteLine("Base");
    }

    void IShowMessage.Show()
    {
        Console.WriteLine("IShowMessage");
    }
}

这么,如果要调用IShowMessage.Show()方法,必须将Base类的实例转型成IShowMessage才行。

        Base b = new Base();
        b.Show();
        ((IShowMessage)b).Show();

体现接口的机能至关主要如下:

1.
当七个接口有签署相同的章程时,一个类可以因此显示接口的措施来还要继续那多个接口。

interface IShowMessage
{
    void Show();
}

interface IPrintMessage
{
    void Show();
}

class Base : IShowMessage, IPrintMessage
{
    public void Show()
    {
        Console.WriteLine("Base");
    }

    void IShowMessage.Show()
    {
        Console.WriteLine("IShowMessage");
    }

    void IPrintMessage.Show()
    {
        throw new NotImplementedException();
    }
}
  1. 因而显式接口来增加类型安全性,从而缩短装箱操作,升高质量

先是是落到实处隐式接口的例证:

using System;

sealed class CLRviaCSharp_15
{
    static void Main(string[] args)
    {
        Base b = new Base();
        b.Show(10);

        Console.ReadKey();
    }
}

interface IShowMessage
{
    void Show(Object o);
}

class Base : IShowMessage
{
    #region IShowMessage Members

    public void Show(object o)
    {
        Console.WriteLine(o.ToString());
    }

    #endregion
}

在调用b.Show(10)时发生装箱操作,通过以下的IL代码(IL_00a)能够见到

.method private static hidebysig 
    void Main (
        string[] args
    ) cil managed 
{
    // Method begins at RVA 0x217c
    // Code size 28 (0x1c)
    .maxstack 2
    .entrypoint
    .locals init (
        [0] class Base b
    )

    IL_0000: nop
    IL_0001: newobj instance void Base::.ctor()
    IL_0006: stloc.0
    IL_0007: ldloc.0
    IL_0008: ldc.i4.s 10
    IL_000a: box int32
    IL_000f: callvirt instance void Base::Show(object)
    IL_0014: nop
    IL_0015: call valuetype [mscorlib]System.ConsoleKeyInfo [mscorlib]System.Console::ReadKey()
    IL_001a: pop
    IL_001b: ret
} // End of method CLRviaCSharp_15.Main

透过呈现达成接口,可以在类Base中定义输出int型的Show方法,代码如下:

using System;

sealed class CLRviaCSharp_15
{
    static void Main(string[] args)
    {
        Base b = new Base();
        b.Show(10);

        Console.ReadKey();
    }
}

interface IShowMessage
{
    void Show(Object o);
}

class Base : IShowMessage
{
    public void Show(int i)
    {
        Console.WriteLine(i.ToString());
    }

    #region IShowMessage Members

    void IShowMessage.Show(object o)
    {
        throw new NotImplementedException();
    }

    #endregion
}

查看Main函数的IL代码,已经没有了前头的装箱操作

.method private static hidebysig 
    void Main (
        string[] args
    ) cil managed 
{
    // Method begins at RVA 0x217c
    // Code size 23 (0x17)
    .maxstack 2
    .entrypoint
    .locals init (
        [0] class Base b
    )

    IL_0000: nop
    IL_0001: newobj instance void Base::.ctor()
    IL_0006: stloc.0
    IL_0007: ldloc.0
    IL_0008: ldc.i4.s 10
    IL_000a: callvirt instance void Base::Show(int32)
    IL_000f: nop
    IL_0010: call valuetype [mscorlib]System.ConsoleKeyInfo [mscorlib]System.Console::ReadKey()
    IL_0015: pop
    IL_0016: ret
} // End of method CLRviaCSharp_15.Main

显式接口还有一些索要留意的地点是,显式接口不能由派生类调用。

4. 接口和基类

“接口和基类的关系,以及何时使用接口,哪一天使用基类。”是在设计时平日须求考虑的题材。

已经有这几个文章对此举办了座谈,那里要说的是那两件事足以而且做。

即:概念一个接口,同时提供一个兑现了那么些接口的基类

.net
Framework中的就有这么的例证,比如IComparable接口就有Comparable类提供的默许完成。

C#,例如上边的事例,即使MyClass中绝非兑现IShowMessage的代码也不在乎,因为ShowMessage提供了默许达成。

interface IShowMessage
{
    void Show(Object o);
}

class ShowMessage : IShowMessage
{
    #region IShowMessage Members

    public void Show(object o)
    {
        Console.WriteLine(o.ToString());
    }

    #endregion
}

class MyClass : ShowMessage , IShowMessage
{
}

主要内容:

  • 接口的一连
  • 显式接口
  • 泛型接口和约束
  • 接口和浮泛类 

相关文章