C# 接口(Interface)

在人类世界中,两个或两个以上的人之间的契约约束他们按照契约行事。同样,接口包括相关功能的声明。实现接口的实体必须提供声明功能的实现。

在C#中,可以使用 interface 关键字定义接口。接口可以包含方法,属性,索引器和事件的声明。但是,它不能包含字段,自动实现的属性。

以下接口声明了文件操作的一些基本功能。

interface IFile
{
    void ReadFile();
    void WriteFile(string text);
}

您不能将访问修饰符应用于接口成员。默认情况下,所有成员都是公开的。如果在接口中使用访问修饰符,则C#编译器将给出编译时错误“The modifier 'public/private/protected' is not valid for this item.”。(Visual Studio将立即显示错误而不进行编译。)

interface IFile
{
    protected void ReadFile(); //编译时错误
    private void WriteFile(string text);//编译时错误
}

接口只能包含声明,而不能包含实现。以下将给出编译时错误。

interface IFile
{
    void ReadFile();
    void WriteFile(string text){
        Console.Write(text);  //错误:无法实现方法
    }
}

实现接口

一个类或一个Struct可以使用冒号(:)实现一个或多个接口。  

语法:

<Class or Struct Name> : <Interface Name>

例如,下面的类隐式地实现了 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 接口。它使用 public 访问修饰符定义 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>来显式实现。 当类正在实现多个接口时,显式实现是有用的;因此,它更易于读,并消除了混乱。 如果接口具有相同的方法名,那么它也是有用的。

不要将 public 修饰符与显式实现一起使用。它将给出一个编译时错误。
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")//编译时错误 
        
        file2.Search("text to be searched");
        //file2.ReadFile(); //编译时错误 
        //file2.WriteFile("content"); //编译时错误 
    }
}

在上面的示例中,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(); //编译时错误 
        //file1.SearchFile("text to be searched"); //编译时错误 
        
        file2.OpenBinaryFile();
        file2.ReadFile();
        //file2.SearchFile("text to be searched"); //编译时错误 
    
        file3.Search("text to be searched");
        //file3.ReadFile(); //编译时错误 
        //file3.OpenBinaryFile(); //编译时错误 
    }
}

上面,FileInfo实现了两个接口,IFile和IBinaryFile显式实现。建议在实现多个接口时显式实现接口,以避免混淆和提高可读性。

要记住的要点:
  1. 接口可以包含方法,属性,索引器和事件的声明。

  2. 接口不能包含私有成员,受保护成员或内部成员。默认情况下,所有成员都是公开的。

  3. 接口不能包含字段和自动实现的属性。

  4. 类或结构可以隐式或显式实现一个或多个接口。在隐式实现接口时使用public修饰符,而在显式实现的情况下请勿使用它。

  5. 使用 InterfaceName. MemberName 显式实现接口。

  6. 一个接口可以继承一个或多个接口。