C#学习笔记—接口
1、接口就是一组抽象成员的集合,表示某个类或结构可以选择去实现的行为,一个类(或者一个结构)可以支持任意数量的接口,因此也就支持了多种行为。
接口与抽象基类的区别:a、虽然类定义了一组抽象成员,但它完全可以再定义许多构造函数、字段数据、非抽象成员(具有实现)等;而接口只能包含抽象成员。b、由抽象父类创建的多态接口有一个主要的限制,那就是只有派生类型才支持由抽象父类定义的成员。接口类型就是来解决这个问题的,在定义了接口之后,它就可以被任何层次结构、任何命名空间或任何程序集中的任何类型实现。c、传统抽象基类的另外一个限制就是每一个派生类型必须处理这一组抽象成员并且提供实现,接口则无此限制。
2、接口不指定基类,而接口的成员也不指定修饰符,所有接口成员都是隐式公共的和抽象的;当我们定义接口成员是,不需要为这个成员实现作用域,接口是纯粹的协议,因此也不会定义实现。(接口不能有字段、不能有构造函数、不能提供实现);不能像类或结构一样分配接口类型。
3、在运行时判断一个类型是否支持一个指定接口的一种方式是使用显式强制转换,如果这个类型不支持被请求的接口,将收到一个无线转换异常。
1 //捕获可能发生的InvalidCastException异常
2 Circle c = new Circle();
3 IPointy itfPt = null;
4 try
5 {
6 itfPt = (IPointy)c;
7 Console.WriteLine(itfPt.Points);
8 }
9 catch (InvalidCastException e)
10 {
11 Console.WriteLine(e.Message);
12 }
4、判断一个指定类型是否支持一个接口的第二种方式就是使用as关键字,若是,则得到指向该对象接口的引用,否则返回null。
1 Hexagon hex2 = new Hexagon("Peter");
2 IPointy itfPt2 = hex2 as IPointy;
3
4 if (itfPt2 != null)
5 Console.WriteLine(itfPt2.Points);
6 else
7 Console.WriteLine("OOPS! Not pointy...");
5、还可以使用is关键字来检查是否实现一个接口,如果要考察的对象与指定接口不符,将返回false值。
1 //生产Shape数组
2 Shape[] myShapes = { new Hexagon(), new Circle(), new Triangle("Joe"), new Circle("JOJO")};
3
4 for (int i = 0; i < myShapes.Length; i++)
5 {
6 //Shape基类定义一个抽象的Draw()成员,由此所有Shape都知道如何绘制自己
7 myShapes[i].Draw();
8
9 //哪些是有棱角的
10 if (myShapes[i] is IPointy)
11 Console.WriteLine("Points:{0}", ((IPointy)myShapes[i]).Points);
12 else
13 Console.WriteLine("{0}\'s not pointy!", myShapes[i].PetName);
14 Console.WriteLine();
15 }
6、接口作为参数。如果有某些类以及实现了IDraw3D接口,然后定义一个将IDraw3D接口作为参数的方法,将能有效传递任何实现IDraw3D接口的对象。
//绘制任何支持IDraw3D接口的类型
static void DrawIn3D(IDraw3D itf3d)
{
Console.WriteLine("Drawing IDraw3D compatible type");
itf3d.Draw3D();
}
//支持绘制为3D吗
if (myShapes[i] is IDraw3D)
DrawIn3D((IDraw3D)myShapes[i]);
7、接口也可以被用来作为方法的返回值。
1 //这个方法返回数组中的第一个实现了IPointy的对象
2 static IPointy FindFirstPointyShape(Shape[] shapes)
3 {
4 foreach (Shape s in shapes)
5 {
6 if (s is IPointy)
7 return s as IPointy;
8 }
9 return null;
10 }
11
12 //生产Shape数组
13 Shape[] myShapes = { new Hexagon(), new Circle(), new Triangle("Joe"), new Circle("JOJO")};
14
15 //获取第一个pointy项
16 //为了安全起见,在使用前最好检查firstPointyItem是否为null
17 IPointy firstPointyItem = FindFirstPointyShape(myShapes);
18 Console.WriteLine("The item has {0} points", firstPointyItem.Points);
8、接口类型数组
1 //这个数组只能包含实现了IPointy接口的类型
2 IPointy[] myPointyObjects = { new Hexagon(), new Triangle()};
3
4 foreach (IPointy i in myPointyObjects)
5 Console.WriteLine("Object has {0} points.", i.Points);
9、通过显式接口解决命名冲突。如果显式实现接口成员的话,大致模式可以归结为:
returnType InterfaceName.MethodName(parms)
使用这种语法时,不能提供访问修饰符,显式实现的成员总是自动为私有的。由于显式实现的成员总是隐式私有的,这些成员在对象级别就不可用,因此我们必须使用显式转换来访问需要的功能(强制转换、is或as关键字)。
10、设计接口层次。和类层次结构相似,如果接口扩展了既有接口,它就继承了父接口定义的抽象成员,当然,和基于类的继承不同的是,派生接口不会继承真正的实现,而只是通过额外的抽象成员扩展了其自身的定义。
11、接口在以下情况特别有用:a、只有一个层次结构,但是只有一部分派生类支持某个公共行为;b、需要构建的公共行为跨多个层次结构,而且除了System.Object以为,没有其他公共父类。