interfaces
are the primary means of decoupling the uses of a class from its implementation. This decoupling provides flexibility for maintenance of the implementation and helps support type safe generic behavior.
The syntax of an interface is similar to that of a class or struct except that methods and properties appear as the signature only and no body is provided.
public interface ILanguage
{
string Speak();
}
public interface IItalianLanguage : ILanguage
{
string Speak();
string SpeakItalian();
}
public interface IScriptConverter
{
string Version { get; set; }
string ConvertCyrillicToLatin(string cyrillic);
}
The implementing class or struct must implement all operations defined by the interface.
Interfaces typically do one or more of the following:
IComparable<T>
) orpublic class ItalianTraveller : IItalianLanguage
{
public string Speak()
{
return "Ciao mondo";
}
public string SpeakItalian()
{
return Speak();
}
}
public class ItalianTravellerV2 : IItalianLanguage
{
public string Speak()
{
return "migliorata - Ciao mondo";
}
public string SpeakItalian()
{
return Speak();
}
}
public class FrenchTraveller : ILanguage
{
public string Speak()
{
return "Ça va?";
}
}
public class RussianTraveller : ILanguage, IScriptConverter
{
public string Version { get; set; } = "1.0";
public string Speak()
{
return "Привет мир";
}
public string ConvertCyrillicToLatin(string cyrillic)
{
throw new NotImplementedException();
}
}
public class DocumentTranslator : IScriptConverter
{
public string Version { get; set; } = "1.0";
public string Translate(string russian)
{
throw new NotImplementedException();
}
public string ConvertCyrillicToLatin(string cyrillic)
{
throw new NotImplementedException();
}
}
Code which uses the above interfaces and classes can:
Interfaces are widely used to support testing as they allow for easy mocking.
See this article for details of what types of member can be included in an interface.
Interfaces can inherit from other interfaces.
Members of an interface are public by default.
Interfaces can contain nested types, such as const
literals, enums
, delegates
, classes
and structs
. Here, the interfaces act as namespaces in the same way that classes and structs do and the behavior and syntax is identical.
By design, C# does not support multiple inheritance, but it facilitates a kind of multiple inheritance through interfaces.
Moreover, the concept of polymorphism can be implemented through interfaces underpins the interface mechanism.
Sometimes method names and signatures can be shared in two different interfaces. In order provide a distinct implementation of these methods, C# provides explicit implementation of interfaces. Note that to use a particular implementation of an interface you need to convert the expression containing referencing the object to that interface. Assignment, casting or passing as a parameter will achieve this.
public interface IFoo
{
void X();
}
public interface IBar
{
void X();
}
public class Census : IFoo, IBar
{
void IFoo.X()
{
Console.Write("This is from Foo");
}
void IBar.X()
{
Console.Write("This is from Bar");
}
}
public class User
{
public void Use()
{
IFoo foo = new Census();
IBar bar = new Census();
foo.X();
// => "This is from Foo"
bar.X();
// => "This is from Bar"
}
}
There are a number of use cases:
IEnumerable.GetEnumerator()
, alongside IEnumerable<T>.GetEnuerator()
, is required. You may never make use of such the interface but the compiler may insist.IFormattable
has a ToString()
method which takes a format type parameter as well as parameter of type IFormatProvider
. A class like FormattableString
from the Base Class Library (BCL) has the interface to ensure it can be used by routines that take an IFormattable
but it is more expressive for its main version of ToString(IFormatProvider)
to omit the format type parameter as it is not used in the implementation and would confuse API users.Version 8 of C# addresses a nagging problem with APIs. If you add methods to an interface to enhance functionality for new implementations then it is necessary to modify all the existing implementations of the interface so that they comply with the API-contract even though they have no implementation specific behavior. C# now allows for a default method to be provided as part of the interface (Java developers will be familiar). Previously, when such a change occurred a version 2 of the interface would exist alongside the original.
This article is an excellent primer on interfaces and focuses on default implementation and other supporting innovations such as static
, private
and virtual
members.