C# - 接口
在人类世界中,两个人或多人之间的合同约束他们按照合同行事。同样,接口包含相关功能的声明。实现接口的实体必须提供所声明功能的实现。
在 C# 中,可以使用 interface
关键字定义接口。接口可以包含方法、属性、索引器和事件的声明。但是,它不能包含实例字段。
以下接口声明了文件操作的一些基本功能。
interface IFile
{
void ReadFile();
void WriteFile(string text);
}
以上声明了一个名为 IFile
的接口。(建议接口名称以字母 "I" 开头,以便容易区分它是接口而不是类。)IFile
接口包含两个方法,ReadFile()
和 WriteFile(string)
。
- 接口可以包含方法、属性、索引器和事件的声明。
- 从 C# 8.0 开始支持具有实现体的默认接口方法。
- 接口不能包含构造函数和字段。
- 接口成员默认是
abstract
和public
。 - 不能将访问修饰符应用于接口成员。但是,从 C# 8.0 开始,在某些条件下可以使用 private、protected、internal、public、virtual、abstract、sealed、static、extern 和 partial 修饰符。
实现接口
类或结构可以使用冒号 :
实现一个或多个接口。在实现接口时,必须覆盖接口的所有成员。
class ClassName : InterfaceName
{
}
例如,以下 FileInfo
类实现了 IFile
接口,因此它应该覆盖 IFile
的所有成员。
interface IFile
{
void ReadFile();
void WriteFile(string text);
}
class FileInfo : IFile
{
public void ReadFile()
{
Console.WriteLine("Reading File");
}
public void WriteFile(string text)
{
Console.WriteLine("Writing to file");
}
}
在上面的示例中,FileInfo
类实现了 IFile
接口。它使用公共访问修饰符覆盖了 IFile
接口的所有成员。FileInfo
类还可以包含接口成员之外的其他成员。
public
修饰符实现;否则,编译器将给出编译时错误。您可以创建类的对象并将其分配给接口类型的变量,如下所示。
public class Program
{
public static void Main()
{
IFile file1 = new FileInfo();
FileInfo file2 = new FileInfo();
file1.ReadFile();
file1.WriteFile("content");
file2.ReadFile();
file2.WriteFile("content");
}
}
上面,我们创建了 FileInfo
类的对象,并将其分配给 IFile
类型变量和 FileInfo
类型变量。当接口隐式实现时,您可以使用 IFile
类型变量以及 FileInfo
类型变量访问 IFile
成员。
显式实现
接口可以使用 <InterfaceName>.<MemberName>
进行显式实现。当类实现多个接口时,显式实现非常有用;因此,它更具可读性并消除了混淆。如果接口恰好具有相同的方法名称,它也很有用。
interface IFile
{
void ReadFile();
void WriteFile(string text);
}
class FileInfo : IFile
{
void IFile.ReadFile()
{
Console.WriteLine("Reading File");
}
void IFile.WriteFile(string text)
{
Console.WriteLine("Writing to file");
}
}
当您显式实现接口时,只能通过接口类型的实例访问接口成员。
interface IFile
{
void ReadFile();
void WriteFile(string text);
}
class FileInfo : IFile
{
void IFile.ReadFile()
{
Console.WriteLine("Reading File");
}
void IFile.WriteFile(string text)
{
Console.WriteLine("Writing to file");
}
public void Search(string text)
{
Console.WriteLine("Searching in file");
}
}
public class Program
{
public static void Main()
{
IFile file1 = new FileInfo();
FileInfo file2 = new FileInfo();
file1.ReadFile();
file1.WriteFile("content");
//file1.Search("text to be searched")//compile-time error
file2.Search("text to be searched");
//file2.ReadFile(); //compile-time error
//file2.WriteFile("content"); //compile-time error
}
}
在上面的示例中,file1
对象只能访问 IFile
的成员,而 file2
只能访问 FileInfo
类的成员。这是显式实现的限制。
实现多个接口
类或结构可以实现多个接口。它必须提供所有接口所有成员的实现。
interface IFile
{
void ReadFile();
}
interface IBinaryFile
{
void OpenBinaryFile();
void ReadFile();
}
class FileInfo : IFile, IBinaryFile
{
void IFile.ReadFile()
{
Console.WriteLine("Reading Text File");
}
void IBinaryFile.OpenBinaryFile()
{
Console.WriteLine("Opening Binary File");
}
void IBinaryFile.ReadFile()
{
Console.WriteLine("Reading Binary File");
}
public void Search(string text)
{
Console.WriteLine("Searching in File");
}
}
public class Program
{
public static void Main()
{
IFile file1 = new FileInfo();
IBinaryFile file2 = new FileInfo();
FileInfo file3 = new FileInfo();
file1.ReadFile();
//file1.OpenBinaryFile(); //compile-time error
//file1.SearchFile("text to be searched"); //compile-time error
file2.OpenBinaryFile();
file2.ReadFile();
//file2.SearchFile("text to be searched"); //compile-time error
file3.Search("text to be searched");
//file3.ReadFile(); //compile-time error
//file3.OpenBinaryFile(); //compile-time error
}
}
上面,FileInfo
显式实现了两个接口 IFile
和 IBinaryFile
。在实现多个接口时,建议显式实现接口,以避免混淆并提高可读性。
默认接口方法
到目前为止,我们了解到接口只能包含方法声明。C# 8.0 增加了对接口中带有具体实现的虚拟扩展方法的支持。
虚拟接口方法也称为默认接口方法,不需要在类或结构中实现。
interface IFile
{
void ReadFile();
void WriteFile(string text);
void DisplayName()
{
Console.WriteLine("IFile");
}
}
在上面的 IFile
接口中,DisplayName()
是默认方法。对于所有实现 IFile
接口的类,实现将保持不变。请注意,类不从其接口继承默认方法;因此,不能使用类实例访问它。
class FileInfo : IFile
{
public void ReadFile()
{
Console.WriteLine("Reading File");
}
public void WriteFile(string text)
{
Console.WriteLine("Writing to file");
}
}
public class Program
{
public static void Main()
{
IFile file1 = new FileInfo();
file1.ReadFile();
file1.WriteFile("content");
file1.DisplayName();
FileInfo file2 = new FileInfo();
//file2.DisplayName(); //compile-time error
}
}
了解更多关于默认接口方法的信息。
接口中的修饰符
C# 8.0 允许在接口中使用 private、protected、internal、public、virtual、abstract、sealed、static、extern 和 partial 修饰符。
- 所有接口成员的默认访问级别为
public
。 - 包含方法体的接口成员是
virtual
成员,除非使用了sealed
或private
修饰符。 - 接口的
private
或sealed
函数成员必须具有实现体。 - 接口可以声明静态成员,可以通过接口名称访问。
了解更多关于接口中修饰符的信息。