6.C#编程指南-接口
接口描述的是可属于任何类或结构的一组相关功能。接口使用interface关键字进行定义,如下面的示例所示。
interface IEquatable<T> { bool Equals(T obj); }
接口可由方法、属性、事件、索引器或这四类成员类型的任意组合构。接口不能包含常量、字段、运算符、实例构造函数、析构函数或类型。它不能包含静态成员。接口成员是自动公开的,且不能包含任何访问修饰符。
类或结构实现接口时,该类或结构将为该接口定义的所有成员提供实现。接口本身不提供类或结构能够以继承基类功能的方式继承的任何功能。但是,如果基类实现接口,派生类将继承该实现。派生的类被认为是隐式地实现接口。
类和结构按照类继承基类或结构的类似方式实现接口,但有两个例外:
- 类或结构可实现多个接口。
- 类或结构实现接口时,仅接收方法名称和签名,因为接口本身不包含实现,如下面的示例所示。
public class Car : IEquatable<Car> { public string Make {get; set;} public string Model { get; set; } public string Year { get; set; } // Implementation of IEquatable<T> interface public bool Equals(Car car) { if (this.Make == car.Make && this.Model == car.Model && this.Year == car.Year) { return true; } else { return false; } } }
显示接口实现
如果类实现两个接口,并且这两个接口包含具有相同签名的成员,那么在类中实现该成员将导致两个接口都使用该成员作为它们的实现。例如:
interface IControl { void Paint(); } interface ISurface { void Paint(); } public class SampleClass : IControl, ISurface { void IControl.Paint() { System.Console.WriteLine("IControl.Paint"); } void ISurface.Paint() { System.Console.WriteLine("ISurface.Paint"); } } //类成员 IControl.Paint 只能通过 IControl 接口使用,ISurface.Paint 只能通过 ISurface 使用。 两个方法实现都是分离的,都不可以直接在类中使用。 SampleClass obj = new SampleClass(); //obj.Paint(); // Compiler error. IControl c = (IControl)obj; c.Paint(); // Calls IControl.Paint on SampleClass. ISurface s = (ISurface)obj; s.Paint(); // Calls ISurface.Paint on SampleClass.
注意:显式实现的接口成员不能从类实例访问
如何:显示实现两个接口的成员
显式接口实现还允许程序员实现具有相同成员名称的两个接口,并为每个接口成员各提供一个实现。 本示例同时以公制单位和英制单位显示框的尺寸。 Box 类实现 IEnglishDimensions 和 IMetricDimensions 两个接口,它们表示不同的度量系统。 两个接口有相同的成员名称 Length 和 Width。
// Declare the English units interface: interface IEnglishDimensions { float Length(); float Width(); } // Declare the metric units interface: interface IMetricDimensions { float Length(); float Width(); } // Declare the Box class that implements the two interfaces: // IEnglishDimensions and IMetricDimensions: class Box : IEnglishDimensions, IMetricDimensions { float lengthInches; float widthInches; public Box(float length, float width) { lengthInches = length; widthInches = width; } // Explicitly implement the members of IEnglishDimensions: float IEnglishDimensions.Length() { return lengthInches; } float IEnglishDimensions.Width() { return widthInches; } // Explicitly implement the members of IMetricDimensions: float IMetricDimensions.Length() { return lengthInches * 2.54f; } float IMetricDimensions.Width() { return widthInches * 2.54f; } static void Main() { // Declare a class instance box1: Box box1 = new Box(30.0f, 20.0f); // Declare an instance of the English units interface: IEnglishDimensions eDimensions = (IEnglishDimensions)box1; // Declare an instance of the metric units interface: IMetricDimensions mDimensions = (IMetricDimensions)box1; // Print dimensions in English units: System.Console.WriteLine("Length(in): {0}", eDimensions.Length()); System.Console.WriteLine("Width (in): {0}", eDimensions.Width()); // Print dimensions in metric units: System.Console.WriteLine("Length(cm): {0}", mDimensions.Length()); System.Console.WriteLine("Width (cm): {0}", mDimensions.Width()); } } /* Output: Length(in): 30 Width (in): 20 Length(cm): 76.2 Width (cm): 50.8 */
如果希望默认度量采用英制单位,请正常实现 Length 和 Width 这两个方法,并从 IMetricDimensions 接口显式实现 Length 和 Width 方法:
// Normal implementation: public float Length() { return lengthInches; } public float Width() { return widthInches; } // Explicit implementation: float IMetricDimensions.Length() { return lengthInches * 2.54f; } float IMetricDimensions.Width() { return widthInches * 2.54f; }
这种情况下,可以从类实例访问英制单位,而从接口实例访问公制单位:
public static void Test() { Box box1 = new Box(30.0f, 20.0f); IMetricDimensions mDimensions = (IMetricDimensions)box1; System.Console.WriteLine("Length(in): {0}", box1.Length()); System.Console.WriteLine("Width (in): {0}", box1.Width()); System.Console.WriteLine("Length(cm): {0}", mDimensions.Length()); System.Console.WriteLine("Width (cm): {0}", mDimensions.Width()); }