介面包含非抽象 class 或 struct 必須實作之一組相關功能的定義。 介面可以定義 static 方法。 介面可以定義成員的預設實作。 介面無法宣告執行個體資料,例如欄位、自動實作的屬性或類似屬性的事件。
例如,您可以藉由使用介面,在類別中包含多個來源的行為。 這項功能在 C# 中是很重要的,因為語言不支援類別的多重繼承。 此外,如果您要模擬結構繼承,則必須使用介面,因為它們實際上無法繼承自另一個結構或類別。
您要使用 interface 關鍵字來定義介面,如下列範例所示。
interface IEquatable<T>
{
bool Equals(T obj);
}
介面的名稱必須是有效的 C# 識別碼名稱。 依慣例,介面名稱的開頭是大寫的|capital I。
任何實作 IEquatable<T> 介面的類別或結構,必須包含 Equals 方法的定義,該方法符合介面指定的簽章。 如此一來,您可以倚賴實作 T 之 IEquatable<T> 類型的類別,以包含 Equals 方法,而且這個類別的執行個體可以使用該方法判斷它是否等於相同類別的另一個執行個體。
IEquatable<T> 的定義不提供 Equals 的實作。 不過,類別或結構可以實作多個介面,但類別只能繼承自單一類別。
如需抽象類別的詳細資訊,請參閱抽象和密封類別以及類別成員。
介面可以包含執行個體方法、屬性、事件、索引子,或以上四個成員類型的組合。 介面可以包含靜態建構函式、欄位、常數或運算子。 非欄位的介面成員可以是 static abstract。 介面不得包含執行個體欄位、執行個體建構函式或完成項。 介面成員預設為公用,而且您可以明確地指定協助工具修飾詞,例如 public、protected、internal、private、protected internal 或 private protected。
private 成員必須有預設實作。
若要使用隱含實作來實作介面成員,實作類別的對應成員必須是公用、非靜態的,而且與介面成員具有相同的名稱和簽章。 你必須使用明確的介面實作來實作那些不應該是公開的介面成員。
注意
當介面宣告靜態成員時,實作該介面的類型也可能宣告具有相同簽章的靜態成員。 這些成員是獨立且由宣告成員的類型唯一識別的。 在類型中宣告的靜態成員不會覆寫在介面中宣告的靜態成員。
實作介面的類別或結構必須為所有宣告的成員提供實作,而不是介面提供的預設實作。 不過,如果基底類別實作介面,則衍生自基底類別的任何類別都會繼承該實作。
下列範例會示範 IEquatable<T> 介面的實作。 實作類別 Car 必須提供 Equals 方法的實作。
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)
{
return (this.Make, this.Model, this.Year) ==
(car?.Make, car?.Model, car?.Year);
}
}
類別的屬性與索引器可以為在介面中宣告的屬性或索引器定義額外的存取者。 例如,介面可能會宣告具有 get 存取子的屬性。 實作介面的類別可以宣告具有 get 和 set 存取子的相同屬性。 不過,如果屬性或索引子使用明確的實作,則存取子必須相符。 如需明確實作的詳細資訊,請參閱明確介面實作和介面屬性。
介面可以繼承自一或多個介面。 衍生介面會繼承其基底介面的成員。 實作衍生介面的類別必須在衍生介面中實作所有成員,包括衍生介面基底介面的所有成員。 該類別可能會隱含地轉換成衍生介面或其任何基底介面。 類別可能透過基底類別包含介面多次,繼承或透過其他介面繼承的介面。 不過,類別只能提供介面實作一次,而且只有在類別將介面宣告為類別 (class ClassName : InterfaceName) 定義的一部分時。 如果因為您繼承實作介面的基底類別而繼承介面,則基底類別會提供介面成員的實作。 不過,衍生的類別可以實作任何虛擬介面成員,而不使用繼承的實作。 當介面宣告方法的預設實作時,實作該介面的任何類別都會繼承該實作 (您必須將類別執行個體轉換成介面類別型,才能存取介面成員上的預設實作)。
基底類別也可以使用虛擬成員來實作介面成員。 在此情況下,衍生的類別可以藉由覆寫虛擬成員來變更介面行為。 如需虛擬成員的詳細資訊,請參閱多型。
使用內部介面
內部介面通常可以使用具有公用成員的隱含實作來實作,只要介面簽章中的所有類型都可以公開存取。 不過,當介面在其成員簽章中使用內部類型時,隱含實作就變得不可能,因為實作類別成員在公開內部類型時必須是公用的。 在這種情況下,您必須使用明確的介面實作。
下列範例顯示這兩種情況:
// Internal type that cannot be exposed publicly
internal class InternalConfiguration
{
public string Setting { get; set; } = "";
}
// Internal interface that CAN be implemented with public members
// because it only uses public types in its signature
internal interface ILoggable
{
void Log(string message); // string is public, so this works with implicit implementation
}
// Interface with internal accessibility using internal types
internal interface IConfigurable
{
void Configure(InternalConfiguration config); // Internal type prevents implicit implementation
}
// This class shows both implicit and explicit interface implementation
public class ServiceImplementation : ILoggable, IConfigurable
{
// Implicit implementation works for ILoggable because string is public
public void Log(string message)
{
Console.WriteLine($"Log: {message}");
}
// Explicit implementation required for IConfigurable because it uses internal types
void IConfigurable.Configure(InternalConfiguration config)
{
// Implementation here
Console.WriteLine($"Configured with: {config.Setting}");
}
// If we tried implicit implementation for IConfigurable, this wouldn't compile:
// public void Configure(InternalConfiguration config) // Error: cannot expose internal type
}
在上述範例中,介面在其 IConfigurable 方法簽章中使用內部類型 InternalConfiguration 。 無法給予 ServiceImplementation 類別隱含實作,因為這需要將 Configure 方法設定為公開,而當方法簽名包含內部類型時,這是不允許的。 相反地,會使用明確的介面實作,它沒有存取修飾符,而且只能透過介面類型存取。
相反地, ILoggable 介面可以使用公用成員隱含實作,因為其簽章 (string) 中的所有類型都可以公開存取,即使介面本身是內部的。
如需明確介面實作的詳細資訊,請參閱 明確介面實作。
介面摘要
介面具有下列屬性:
- 在 C# 8.0 之前的版本中,介面類似只有抽象成員的抽象基底類別。 實作介面的類別或結構必須實作其所有成員。
- 從 C# 8.0 開始,介面可以定義其部分或所有成員的預設實作。 實作介面的類別或結構不需要實作具有預設實作的成員。 如需詳細資訊,請參閱預設介面方法。
- 介面無法直接具現化。
- 類別或結構可以實作多個介面。 類別可以繼承基底類別,也會實作一或多個介面。