首页 > 代码库 > C#接口,你真的掌握了么
C#接口,你真的掌握了么
一、定义接口
接口对一组方法签名进行了统一命名。定义接口类型时,可指定的可见性为public 或 internal,但在[CLR via C#]第3版书中的原话是:"定义接口类型时,可指定你希望的任何可见性/可访问性(public,protected,internal等)",个人认为这句话说得不妥。但无论如何,不嵌套在其他类型中的顶级类型的可访问性只能是 internal 或 public。这些类型的默认可访问性是 internal。
二、继承接口
C#编译器要求将用于实现一个接口的方法简称接口方法标记为public。CLR要求将接口方法标记为virtual。如果在源代码中没有显式地将接口方法标记为virtual,编译器会将它们标记为virtual和sealed;这会阻止派生类重写接口方法。如果显式地将接口方法标记为virtual,编译器就会将此方法标记为virtual并保持它的非密封状态,这样一来,派生类就可以重写它。
值类型可以实现零个或多个接口。不过,将值类型的实例转型为接口类型时,值类型的实例必须装箱。这是由于接口变量是一个引用,它必须指向堆上的一个对象,使CLR能检查对象的类型对象指针,从而判断对象的确切类型。然后,在调用已装箱值类型的一个接口方法时,CLR会跟随对象的类型对象指针,找到类型对象的方法表,从而调用正确的方法。
三、隐式和显式接口方法实现
public class SimpleType : IDisposable
{
//隐式接口方法实现
public void Dispose(){ Console.WriteLine("public Dispose");}
//显式接口方法实现(不允许指定可访问性,但是编译器生成方法的元数据时,其可访问性会被自动设为private)
void IDisposable.Dispose(){Console.WriteLine("IDisposable Dispose")}
}
public static void Main()
{
SimpleType st = new SimpleType();
st.Dispose();//输出结果为"public Dispose"
IDisposable d = st;
d.Dispose();//输出结果为"IDisposable Dispose"
}
四、泛型接口
泛型接口提供的好处:
private void Method1()
{
Int32 x = 1, y = 2;
IComparable c = x;
c.CompareTo(y);//CompareTo期望接收一个Object类型的参数,传递y没有问题,但是值类型会装箱
c.CompareTo("2")//可以编译通过,但是在运行时会抛出异常,无法提供编译时类型安全性
}
private void Method2()
{
Int32 x = 1, y = 2;
IComparable<Int32> c = x;
c.CompareTo(y);//CompareTo期望接收一个Int21类型的参数,传递y没有问题,而且y不会装箱
c.CompareTo("2")//编译错误,可以提供编译时的类型检查
}
1.泛型接口提供了出色的编译时类型安全性。
2.处理值类型时,装箱次数会少得多。
3.类可以实现同一个接口若干次,只要每次使用不同的类型参数
五、在不存在泛型接口版本的情况下,怎样实现来增强编译时的类型安全性
public struct SomeValueType1 : IComparable
{
private Int32 _x;
public SomeValueType(Int32 x){ _x = x; }
public Int32 CompareTo(Object other)
{
return (_x - ((SomeValueType)other)._x);
}
}
public struct SomeValueType2 : IComparable
{
private Int32 _x;
public SomeValueType(Int32 x){ _x = x; }
public Int32 CompareTo(SomeValueType2 other)
{
return (_x - other._x);
}
Int32 IComparable.CompareTo(Object o)
{
return CompareTo((SomeValueTypes)o);
}
}
public static void Main()
{
SomeValueType1 v1 = new SomeValueType1(0);
Object o = new Object();
v1.CompareTo(v1); //值类型进行装箱操作
v1.CompareTo(o) //编译通过,但运行时抛出InvalidCastException,没法进行编译时类型安全的检查
SomeValueType2 v2 = new SomeValueType2(0);
Object o = new Object();
v2.CompareTo(v2); //由于调用的是SomeValueType2自身声明的方法,所以不用装箱
v1.CompareTo(o) //无法通过编译,能提供编译时的类型安全检查
}