C#学习笔记 接口

接口

C#中的接口(interface)在语法上有些类似与抽象类(abstract class),它定义了若干个抽象方法、属性、索引器、事件,形成一个抽象成员的集合,每个成员通常反映事物某些方面的功能。接口在本质上是对某方面功能或特征的约定。
程序中的接口的用处主要体现在下面几个方面:

  • 通过接口可以实现不相关类的相同行为,而不需要考虑这些类之间的层次关系。
  • 通过接口可以指明多个类需要实现的方法。
  • 通过接口可以了解对象的交互界面,而不需要了解对象所对应的类。

定义接口

定义接口使用interface关键字,在接口中可以有多个成员。
一个接口的成员必须是抽象的方法、属性、事件或索引器,这些抽象成员都没有实现体。一个接口不能包含常数、字段、操作符、构造函数、静态构造函数或嵌套类型,也不能包括任何类型的静态成员。
所有接口成员隐含的都有公共访问性,即隐含是public的。但是,接口成员声明中不能使用除new以外的任何修饰符。但接口本身可以带修饰符,如publicinterface。按照编码惯例,接口的名字都以大写字母I开始。例:

public interface IStringList
{
    
    
	void Add(string s);
	int Count{
    
    get;}
	string this[int index]{
    
    get; set;}
}

该接口中包含了一个方法、一个属性和一个索引器。


一个接口可从一个或多个基接口(父接口)中继承。例:

interface IMyInterface:IBase1, IBase2
{
    
    
	void MethodA();
	void MethodB();
}

子接口将继承所有父接口中的属性和方法。也可以利用new修饰符来隐藏父接口中的成员。
例如以下定义(System.Collections.IList的定义):

public interface IList:ICollection, IEnumerable
{
    
    
	bool IsFixedSize{
    
    get;}
	bool IsReadOnly{
    
    get;}
	object this[int index]{
    
    get; set;}
	int Add(object value);
	void Clear();
	bool Contains(object value);
	int IndexOf(object value);
	void Insert(int index, object value);
	void Remove(object value);
	void RemoveAt(int index);
}	

实现接口

接口的声明仅仅给出了抽象方法,相当于程序开发早期的一组协议,而具体地实现接口所规定的的功能,则需某个类为接口中的抽象方法书写语句并定义实在的方法体。
接口可以被类(class)来实现,也可以被结构体(struct)来实现。以下为用类来实现接口的格式:

class 类名:[父类,] 接口, 接口, ..., 接口 
{
    
    
	...
}

一个类在实现接口实,要注意以下问题:

  • 在类的声明部分,用冒号(:)表明其父类及要实现的接口,其中父类一定要放到接口名的前面。如果父类省略,则隐含父类为System.Object
  • 如果一个类实现了某个接口,则要求一定能在该类中找到与该接口的各个成员相对应的成员,也能找到该接口所有的父接口的所有成员。当然,这样的成员可以是在本类中定义的,也可以是从本类的父类中继承过来的。
  • 一个抽象类实现接口时,也要求为所有成员提供实现程序,抽象类可以把接口方法映射到抽象方法中。
  • 一个类只能有一个父类,但是它可以同时实现若干个接口。一个类实现多个接口时,如果把接口理解成特殊的类,那么这个类利用接口实际上就获得了多个父类,即实现了多重继承。
  • 特别注意,接口的抽象方法的访问控制都隐含为public,所以类在实现方法时,必须使用public修饰符。

示例:

using System;

namespace ConsoleApp3接口
{
    
    
	interface Runner
	{
    
    
		void run ();
	}
	interface Swimmer
	{
    
    
		void swim ();
	}
	abstract class Animal
	{
    
    
		abstract public void eat ();
	}

	class Person : Animal, Runner, Swimmer
	{
    
    
		public void run () {
    
    
			Console.WriteLine ("run");
		}
		public void swim () {
    
    
			Console.WriteLine ("swim");
		}
		public override void eat () {
    
    
			Console.WriteLine ("eat");
		}
		public void speak () {
    
    
			Console.WriteLine ("speak");
		}
	}

	class TestInterface
	{
    
    
		static void m1 (Runner r) {
    
    
			r.run ();
		}
		static void m2 (Swimmer s) {
    
    
			s.swim ();
		}
		static void m3 (Animal a) {
    
    
			a.eat ();
		}
		static void m4 (Person p) {
    
    
			p.speak ();
		}
		public static void Main (string[] args) {
    
    
			Person p = new Person ();
			m1 (p);
			m2 (p);
			m3 (p);
			m4 (p);

			Runner a = new Person ();
			a.run ();
		}
	}
}

对接口的引用

接口可以作为一种引用类型来使用,通过这些引用型变量可以访问类所实现的接口中的方法。例如:假如Person类实现了ISwimmable,则可以将Person对象作为ISwimmable来引用:

	Person p = new Person();
	ISwimmable s = p;

同样,如果一个方法需要用一个接口作为参数,则可以直接将一个实现了该接口的类的实例对象传入。把接口作为一种数据类型可以不需要了解对象所对应的具体的类,而着重于它的交互界面或功能。
接口可能有多个父接口,而接口内的成员可能有同名现象,所以,在对接口成员进行调用时,可能出现不明确的现象。例如:

interface IList
{
    
    
	int Count{
    
    get; set;}
}
interface ICounter
{
    
    
	void Count(int i);
}
interface IListCounter : IList, ICounter{
    
    }
class C
{
    
    
	void Test(IListCounter x){
    
    
		x.Count(1);				// Error, Count不明确
		x.Count = 1;			// Error, Count不明确
		((IList)x).Count = 1;	// Ok, 调用IList.Count.set
		((ICounter)x).Count(1);	// Ok, 调用ICounter.Count
	}
}

显示接口成员实现

有时候,多个接口有相同的签名方法(或其他成员),如果一个类要同时实现多个接口,可以只用一个方法即可满足各个接口的要求。然而,在更多的情况下,这些相同签名方法的在各个接口中的含义并不相同,所以要求类在实现各个接口时,要显示指明实现的是哪个接口中的方法。例如:

using System;

namespace ConsoleApp3接口
{
    
    
	class InterfaceExplicitImpl
	{
    
    
		static void Main (string[] args) {
    
    
			FileViewer f = new FileViewer ();
			f.Test ();
			((IWindow)f).Close ();

			IWindow w = new FileViewer ();
			w.Close ();
		}
	}
	
	interface IWindow
	{
    
    
		void Close ();
	}
	interface IFileHander
	{
    
    
		void Close ();
	}
	class FileViewer : IWindow, IFileHander
	{
    
    
		void IWindow.Close () {
    
    
			Console.WriteLine ("Window Closed");
		}

		void IFileHander.Close () {
    
    
			Console.WriteLine ("File Closed");
		}

		public void Test () {
    
    
			((IWindow)this).Close ();
		}
	}
}

从以上可以看出,显示接口成员实现程序跟其他成员相比,具有不同的访问能力特性。因为显示接口成员不能通过类实例来调用,从这个意义上说它们是私有的;而另一方面,它们可以通过一个接口实例来访问,从这个意义上说,它们又是公共的。

显示接口成员实现主要服务于两个目的:

  • 因为显示接口成员不能通过类或结构实例进行访问,只允许通过接口进行访问,所以,经常用语只能通过接口进行访问的情形。
  • 显示接口成员实现 程序允许用相同的签名消除接口成员的歧义,使得一个类或结构可以包含签名相同而返回类型不同的成员。

猜你喜欢

转载自blog.csdn.net/qq_45349225/article/details/113965436