Interface trong C#

Interface được định nghĩa là một hợp đồng mà tất cả các lớp hoặc struct triển khai thực hiện (implement) interface phải tuân theo. Interface xác định phần 'cái gì' của hợp đồng và các lớp dẫn xuất xác định phần 'làm thế nào' của hợp đồng.

Interface khai báo các thuộc tính, phương thức và sự kiện là các thành viên của interface. Interface chỉ khai báo các thành viên, trách nhiệm của lớp dẫn xuất là triển khai thực hiện các thành viên này. Interface thường giúp cung cấp một cấu trúc tiêu chuẩn mà các lớp dẫn xuất sẽ tuân theo.

Các abstract class ở một mức độ nào đó phục vụ cho cùng một mục đích. Tuy nhiên, chúng chủ yếu được sử dụng khi chỉ có một vài phương thức được khai báo bởi lớp cơ sở và lớp dẫn xuất triển khai thực hiện các phương thức này.

Khai báo giao diện

Các interface được khai báo bằng từ khóa interface. Nó tương tự như khai báo lớp.

Các thành viên của interface không có chỉ thị truy cập nhưng mặc định là public. Nếu bạn sử dụng chỉ thị truy cập trong interface thì trình biên dịch C# sẽ đưa ra lỗi khi biên dịch "The modifier 'public/protected' is not valid for this item". Nếu bạn sử dụng Visual Studio để lập trình C# thì nó sẽ hiển thị lỗi ngay lập tức mà không cần biên dịch.

Sau đây là một ví dụ về khai báo interface không hợp lệ:

public interface ITransactions 
{
   public void ShowTransaction(); //error
   protected double GetAmount();  //error
}

Sau đây là một ví dụ về khai báo interface hợp lệ:

public interface ITransactions 
{
   void ShowTransaction();
   double GetAmount();
}

Ví dụ

Ví dụ sau đây cho thấy việc triển khai thực hiện interface trên:

using System.Collections.Generic;
using System.Linq;
using System.Text;
using System;

namespace InterfaceApplication 
{   
   public interface ITransactions 
   {
      void ShowTransaction();
      double GetAmount();
   }
   
   public class Transaction : ITransactions 
   {
      private string code;
      private DateTime date;
      private double amount;
      
      public Transaction() 
      { }
      
      public Transaction(string code, DateTime date, double amount) 
      {
         this.code = code;
         this.date = date;
         this.amount = amount;
      }
      
      public double GetAmount() 
      {
         return amount;
      }
      
      public void ShowTransaction() 
      {
         Console.WriteLine("Transaction: {0}", code);
         Console.WriteLine("Date: {0:dd/MM/yyyy}", date);
         Console.WriteLine("Amount: {0:N0}", amount);
      }
   }
   
   public class Tester 
   {     
      public static void Main(string[] args) 
      {
         Transaction transaction1 = new Transaction("001", new DateTime(2020,4,2), 78900.00);
         Transaction transaction2 = new Transaction("002", new DateTime(2020,4,3), 451900.00);
         
         transaction1.ShowTransaction();
         transaction2.ShowTransaction();
         Console.ReadLine();
      }
   }
}

Khi đoạn mã trên được biên dịch và thực thi, nó tạo ra kết quả sau:

Transaction: 001
Date: 02/04/2020
Amount: 78,900
Transaction: 002
Date: 03/04/2020
Amount: 451,900
Lưu ý: Tất cả các thành viên của interface phải được triển khai thực hiện với chỉ thị truy cập là public trong lớp hoặc struct dẫn xuất. C# sẽ đưa ra lỗi khi biên dịch nếu bất kỳ thành viên nào không sử dụng chỉ thị truy cập public.

Triển khai thực hiện interface tường minh

Nếu lớp của bạn triển khai thực hiện hai interface mà có các thành viên trùng tên thì triển khai tường minh sẽ giúp tránh nhầm lẫn thành viên của 2 interface.

Ví dụ sau sẽ minh họa cho điều trên:

using System;

namespace InterfaceApplication 
{   
   public interface IA 
   {
      void Print();
   }
   public interface IB 
   {
      void Print();
   }
   
   public class C : IA, IB 
   {
      void IA.Print() 
      {
         Console.WriteLine("Print interface IA");
      }
      
      void IB.Print() 
      {
         Console.WriteLine("Print interface IB");
      }
   }
   
   class Tester 
   {     
      static void Main(string[] args) 
      {
         IA a = new C();         
         a.Print();
		  
         IB b = new C();
         b.Print();
         
         Console.ReadLine();
      }
   }
}

Kết quả khi biên dịch và chạy chương trình:

Print interface IA
Print interface IB

Trong ví dụ trên về triển khai tường minh, lưu ý rằng nó không thể sử dụng chỉ thị truy cập public một cách rõ ràng. C# sẽ báo lỗi nếu bạn sử dụng chỉ thị truy cập public khi triển khai thực hiện interface tường minh.

Triển khai thực hiện chung interface

Có thể có nhiều lớp hoặc struct triển khai thực hiện cùng một interface. Hãy xem ví dụ sau:

using System;

namespace AbstractionApplication 
{
   interface IExportData
   {
      void Export();
   }
   
   class TextExport : IExportData 
   {
      public void Export()
      {
         Console.WriteLine("Export data to .txt file");
      }
   }
   
   class CsvExport : IExportData 
   {
      public void Export()
      {
         Console.WriteLine("Export data to .csv file");
      }
   }   
      
   class RectangleTester 
   {
      static void Main(string[] args) 
      {
         IExportData exportData1 = new TextExport();
         exportData1.ExportData();
         
         IExportData exportData2 = new CsvExport();
         exportData2.ExportData();
         
         Console.ReadKey();
      }
   }
}

Kết quả khi biên dịch và chạy chương trình trên:

Export data to .txt file
Export data to .csv file

Như bạn thấy ở ví dụ trên, lớp TextExport và CsvExport cùng triên khai thực hiện từ một interface là IExportData nhưng theo hai cách hoàn toàn khác nhau. Lớp TextExport sẽ xuất dữ liệu ra file .txt còn lớp CsvExport xuất dữ liệu ra file .csv.

Triển khai thực hiện nhiều interface

Một lớp hoặc struct có thể triển khai thực hiện nhiều interface cùng lúc. Ví dụ sau sẽ minh họa cho điều trên:

using System;

namespace InterfaceApplication 
{   
   public interface IPrint
   {
      void Print();
   }
   public interface IExport 
   {
      void Export();
   }
   
   public class Document : IPrint, IExport
   {
      public void Print() 
      {
         Console.WriteLine("Print document");
      }
      
      public void Export() 
      {
         Console.WriteLine("Export document");
      }
   }
   
   class Tester 
   {     
      static void Main(string[] args) 
      {
         Document document = new Document();         
         document.Print();
         document.Export();
         
         Console.ReadLine();
      }
   }
}

Kết quả khi biên dịch và chạy chương trình:

Print document
Export document

Kế thừa interface

Một interface có thể kế thừa từ một hoặc nhiều interface khác. Ví dụ sau sẽ minh họa cho điều trên:

interface IPen
{
    string Color { get; set; }
    bool Open();
    bool Close();
    void Write(string text);
}

interface IBrandedPen : IPen 
{
    string GetBrandName();
}

Những điểm cần nhớ:

  • Một interface chỉ chứa các khai báo về phương thức, thuộc tính, indexer và event.
  • Một lớp hoặc struct có thể triển khai thực hiện một hoặc nhiều interface.
  • Một lớp hoặc struct triển khai thực hiện một interface, phải sử dụng chỉ thị truy cập public cho các thành viên của interface.
  • Không sử dụng chỉ thị truy cập trong interface vì tất cả các thành viên mặc định là public. C# sẽ đưa ra lỗi khi biên dịch nếu được sử dụng chỉ thị truy cập cho các thành viên của interface.
  • Triển khai thực hiện interface tường minh bằng cách sử dụng tiền tố InterfaceName.với tất cả các thành viên và không có chỉ thị truy cập.
  • Một interface có thể kế thừa một hoặc nhiều interface khác.
Lập Trình C#Lập Trình C# Cơ Bản
Bài Viết Liên Quan:
int[] và int[,] trong C#: Ai nhanh hơn
Trung Nguyen 10/10/2020
int[] và int[,] trong C#: Ai nhanh hơn

Hiểu được sự khác biệt giữa các loại mảng trong C# sẽ giúp bạn chọn cấu trúc dữ liệu chính xác cho mọi trường hợp.

Struct và class trong C#: Ai nhanh hơn
Trung Nguyen 09/10/2020
Struct và class trong C#: Ai nhanh hơn

Trong bài viết này, tôi sẽ so sánh sự khác biệt về hiệu suất giữa struct và class trong C#: Ai nhanh hơn.

Best practice cho performance trong C#
Trung Nguyen 03/10/2020
Best practice cho performance trong C#

Mục tiêu của bài viết này là cung cấp một danh sách không đầy đủ các code mẫu cần tránh, vì chúng rủi ro hoặc performance kém.

Đọc ghi file (File I/O) trong C#
Trung Nguyen 26/04/2020
Đọc ghi file (File I/O) trong C#

Hướng dẫn này sẽ giúp bạn tìm hiểu về đọc ghi file (File I/O) trong C# và sử dụng các lớp tiện ích để đọc ghi file.