Example: A simple interface definition:
interface IBook { string GetSummary(); // method int Rating { get; set; } // property event EventHandler BookUpdated; // event string this[string isbn] { get; set; } // indexer }
Example: Define a 'set' accessor when implementing an interface on a class:
interface ICategory { // The interface defines only the get accessor. string CategoryName { get; } } class BookCategory : ICategory { // The class implements both the get and the set accessor. // When the class is accessed through the interface, only the get accessor is available. // Direct users of the class see both the get and the set accessors. public string CategoryName { get; set; } }
Example: Define an interface with a generic type parameter:
// we can have Message<string>, Message<Email>, Message<ForumPost>, etc. interface IMessage<T> { void Send(T msg); IEnumerable<T> All(); }
Explicit interface implementation allows us to provide methods (or other class members) that can be accessed only when using the interface directly. Effectively, explicit interface implementation hides the implemented methods from a class's public interface.
Explicit interface implementation is useful in the following situations:
Example: Both the Account class and the ITransaction interface define the Add method. By using the explicit interface implementation, we solve the name collision and give separate implementation to each Add method. The ITransaction.Add method can only be called through the interface.
interface ITransaction { void Add(decimal amount); } class Account : ITransaction { // A class method accessed implicitly. public void Add(decimal amount) { Console.WriteLine("Account.Add {0}", amount); } // A method that implements the ITransaction interface explicitly. Note that we don't specify // an access modifier. The methods that implement an interface are always public. // Explicit interface implementation is achieved by qualifying an interface method with the name of // the interface. void ITransaction.Add(decimal amount) { Console.WriteLine("ITransaction.Add {0}", amount); } } ... // Call the Add method implemented on the class. Account acc = new Account(); // create the Account object acc.Add(10); // output: Account.Add 10 // Call the Add method implemented on the interface. ITransaction trans = new Account(); // create an interface variable trans.Add(20); // run the explicit implementation; output: ITransaction.Add 20 // Call the Add method implemented on the interface by casting the Account object. ((ITransaction)acc).Add(20); // cast to interface
Example: We have two methods that have the same signatures and different return types. It won't compile as the method overloading does not take into account return types. This is how it may be solved using explicit interface implementation:
public class EnumerableCatalog : IEnumerable<string> { // One of the methods has to use the explicit interface implementation // because they differ only by their return type. public IEnumerator<string> GetEnumerator() { ... } IEnumerator IEnumerable.GetEnumerator() { return this.GetEnumerator(); } }
Interface | Method(s) | Description |
---|---|---|
IComparable | CompareTo(other) | Defines a comparison method that a type implements to sort its instances. |
IComparer | Compare(first, second) | Defines a comparison method that a secondary type implements to sort instances of a primary type. |
IDisposable | Dispose() | Defines a method to release unmanaged resources more efficiently than waiting for a finalizer. |
IFormattable | ToString(format, culture) | Defines a culture-aware method to format the value of an object into a string representation. |
IFormatProvider | GetFormat(type) | Defines a method to format inputs based on a language and region. |
Interfaces with default implementations were introduced in C# 8.0 (available in .NET Core 3.0 or .NET Standard 2.1).
One of the main points of an interface is that it defines a fixed contract. C# 8.0 allows an interface to add new members after release as long as they have a default implementation.