15.接口
接口继承:类型继承的是接口中的方法签名,而非方法实现。
当一个类型继承了一个接口时,它只是在允诺提供其中的方法实现:如果没有提供,则该类型将被认为是抽象的,从而不可能被实例化。
接口仅仅是一个包含着一组虚方法的抽象类型,其中每一个方法都有他们的名称、参数和返回值类型。但接口方法不包括任何实现。
接口也可以定义事件、无参属性以及含参属性,因为它们都只不过是映射到方法上的语法缩写而已。
如果在一个类型内实现接口方法的时候忽略了virtual关键字,那么该方法将被认为是一个密封的虚方法,继承了该实现类型的其他类型将不可以再重写该方法。
当一个类型“继承”某个接口时,它不仅要实现该接口定义的所有方法,还要实现该接口从其他接口中“继承”而来的所有方法。
实现了多个接口的类型允许我们将它的对象看作这些接口中的任何一个。
什么时候使用接口???1… 2… 3…
接口举例:
1.使用接口改变已装箱值类型中的字段
struct Point
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
{
public int x,y;
public void Change(int x,int y)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
this.x=x; this.y=y;
}
public override String ToString()
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
return String.Format("({0},{1})",x,y);
}
}
class Program
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
{
static void Main(string[] args)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
Point p=new Point();
p.x=p.y=1;
p.Change(2,2);
Console.Write(p); //实现System.Iformattable接口,调用ToString方法
Object o=p; //o指向装箱后的Point对象,显示(2,2)
Console.Write(o);
((Point) o).Change(3,3);
Console.Write(o); //拆箱,将已装箱Point中的字段拷贝到线程堆栈上的一个临时 Point中,这个临时Point上的字段值改为3,但已装箱的Point对象不受这种改变的影响,显示(2,2)
}
}
问题出现了,C#不允许我们改变已装箱值类型中的字段
,下面利用接口做一个修订:
interface IChangeBoxedPoint
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
{
void Change(Int32 x, Int32 y);
}
struct Point : IChangeBoxedPoint
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
{
public Int32 x, y;
public void Change(Int32 x, Int32 y)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
this.x = x; this.y = y;
}
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//*![](https://www.cnblogs.com/Images/dot.gif)
![](https://www.cnblogs.com/Images/dot.gif)
![](https://www.cnblogs.com/Images/dot.gif)
.*/
}
class App
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
{
static void Main()
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
Point p=new Point();
object o=new object();
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
/**//*![](https://www.cnblogs.com/Images/dot.gif)
![](https://www.cnblogs.com/Images/dot.gif)
![](https://www.cnblogs.com/Images/dot.gif)
![](https://www.cnblogs.com/Images/dot.gif)
![](https://www.cnblogs.com/Images/dot.gif)
![](https://www.cnblogs.com/Images/dot.gif)
.*/
((IChangeBoxedPoint)p).Change(4, 4); //p装箱,改变已装箱对象,但当Change返回后,已装箱对象立即被垃圾回收
Console.WriteLine(p); //(2,2)
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
((IChangeBoxedPoint)o).Change(5, 5); //这里没有装箱的必要,于是改变已装箱对象Point的值
Console.WriteLine(o); //(5,5) C#中没有接口方法做不到这一点
}
}
2.显示接口成员的实现
public interface IComparable
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
{
Int32 CompareTo(object other);
}
struct SomeValueType:IComparable
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
{
private Int32 x;
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
public SomeValueType(Int32 x)
{ this.x = x; }
public Int32 CompareTo(SomeValueType other)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
return (x - other.x);
}
Int32 IComparable.CompareTo(object other)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
return CompareTo((SomeValueType)other);
}
}
public static void Main()
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
{
SomeValueType v1 = new SomeValueType(1);
SomeValueType v2 = new SomeValueType(2);
Int32 n;
n= v1.CompareTo(v2); //不进行任何装箱
n = ((IComparable)v1).CompareTo(v2); //v2强制装箱
}
注意三点:a.CompareTo方法的名字前加了接口限定名IComparable.CompareTo,它告诉CLR只有在使用一个IComparable对象引用时方法才被调用
b.IComparable.CompareTo的实现是将other转型为SomeValueType后,通过调用CompareTo方法来完成的
c.IComparable.CompareTo方法前没有public或protected访问修饰符
显示接口方法的好处:类型安全,减少装箱操作
16.定制特性
C#中,将定制特性放在紧挨这目标元素前的一个方括号中。
任何人都可以使用定制特性来定义一些信息,并将这些信息应用于几乎所有的元数据表项上,然后在运行时通过查询这些可扩展的元数据信息来动态地改变代码的执行方式。
//待补充……