English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

C# Основы教程

C# Уровень 2教程

C# ООП (面向对象)

Интерфейсы (Interface) в C#

В человеческом мире договорные обязательства约束两个或 более людей выполнять свои обязательства по договору. Таким же образом, интерфейс включает в себя декларации связанных функций. Сущность, реализующая интерфейс, должна предоставить реализацию декларированных функций.

В C# можно использовать ключевое слово interface для определения интерфейса. Интерфейс может содержать декларации методов, свойств, индексаторов и событий. Однако, он не может содержать поля и автоматически реализованные свойства.

Ниже приведен пример интерфейса, который объявляет некоторые базовые функции работы с файлами.

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

Вы не можете применить модификаторы доступа к членам интерфейса. По умолчанию все члены являются общедоступными. Если в интерфейсе используются модификаторы доступа, компилятор C# выдаст ошибку компиляции 'Модификатор 'public/private/protected' недопустим для этого элемента.' (Visual Studio будет немедленно показывать ошибку без компиляции).

interface IFile
{
    protected void ReadFile(); //Ошибка компиляции
    private void WriteFile(string text); //Ошибка компиляции
}

Интерфейс может содержать только декларации, но не реализацию. Напомним, что при использовании деклараций в интерфейсе может возникнуть ошибка компиляции.

interface IFile
{
    void ReadFile();
    void WriteFile(string text){
        Console.Write(text); //Ошибка: метод не может быть реализован
    }
}

Реализация интерфейса

Класс или структура может использовать двоеточие (:) для реализации одного или нескольких интерфейсов.  

Синтаксис:

<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. Он определяет всех членов интерфейса IFile с помощью модификатора доступа public. Класс 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. Одна интерфейс может наследовать один или несколько интерфейсов.