A C# egyik speciális nyelvi eleme a felület, angolul Interface. Ezeken keresztül van megvalósítva a többszörös öröklési rendszer. Egy osztálynak csak egy közvetlen őse lehet, viszont az osztály korlátlan számú interfészt megvalósíthat. Interfészt struktúrák is megvalósíthatnak.
Az intefész felfogható egy viselkedés sablonként. A működésük és viselkedésük kicsit hasonlít az absztrakt osztályokéhoz, de néhány tekintetben mégis eltér.
A hasonlóság annyi, hogy a felületet nem lehet példányosítani, csak az interfészt megvalósító osztályt. Interfészek esetén megvalósításról beszélünk öröklés helyett, mert a interfészek csak absztrakt definíciókat tartalmazhatnak. Tehát egy felület tartalmazhat metódusokat és tulajdonságokat, de adattagokat nem.
Az, hogy megvalósításról beszélünk öröklés helyett, azért lényeges, mert az interfésznél nem szükséges öröklési láncon belül maradni: simán megvalósíthatja ugyanazon interfészt két, egymástól teljesen független osztály.
További eltérés, hogy az intetrfészek esetén a felületben szereplő metódusok és tulajdonságok neve előtt módosító nem szerepelhet, mivel a felületben szereplő összes elemnek publikus elérésűnek kell lennie. Az alábbi példa egy interfészt mutat be:
public interface IPelda
{
void Pelda();
}
Az osztályok a felületeket az öröklés esetén használt szintaxissal valósítják meg. Amennyiben az osztályunk nem implementálja teljesen az adott felületet, akkor fordítási hibát kapunk. Hasonlóan az absztrakt osztályok implementálásához, a Visual Studio szintén segítséget nyújt. Hasonló módszerrel legenerálhatjuk a felület implementáció vázát, ami után “csak” a kódot kell megírnunk.
Az interfészek elnevezésénél íratlan szabály, hogy I betűvel kezdjük őket. Ennek két oka van. Az első ok, hogy így már a név utal arra, hogy az adott elem egy interész. A másik ok pedig az, hogy a .NET keretrendszer beépített felületei is ilyen módon vannak elnevezve. Az alábbi példa az interfészek használatát mutatja be:
using System;
namespace PeldaFelulet
{
interface IPeldaFelulet
{
void PeldaFuggveny();
}
class FeluletImplementacio : IPeldaFelulet
{
public void PeldaFuggveny()
{
Console.WriteLine("Példa függvény implementációja");
}
}
class Program
{
static void Main(string[] args)
{
var pelda = new FeluletImplementacio();
pelda.PeldaFuggveny();
Console.ReadKey();
}
}
}
A program kimenete:
Példa függvény implementációja
A felületek felépítéséből adódóan elkerülhető a gyémánt öröklődés kellemetlen esete. Adódhat persze, hogy két felület tartalmaz azonos névvel ellátott metódusokat, viszont ebben az esetben sincs fordítási hibánk. Ilyen esetben implementációkor explicit módon a metódus, adattag elé ki kell írni, hogy melyik felületi elemet valósítjuk meg. Híváskor is explicit konverzióval kell megoldani a hívást. Az alábbi példa egy ilyen esetet mutat be:
using System;
namespace PeldaFelulet2
{
interface IEgyik
{
string Nevem();
}
interface IMasik
{
string Nevem();
}
class Implementacio : IEgyik, IMasik
{
//alapértelmezetten az objektum IMasik
//vagyis implicit IMasik interfészre konvertálunk
public string Nevem()
{
return "IMasik implementáció";
}
//Explicit implementáció
//megfelelő konvertálás nélkül nem hívható
//Explcit megvalósításkor nem adható meg láthatóság
//automatikusan private lesz
string IEgyik.Nevem()
{
return "IEgyik implementáció";
}
}
class Program
{
static void Main(string[] args)
{
var imp = new Implementacio();
Console.WriteLine(imp.Nevem());
IEgyik i = imp;
//konvertálás után hívható az implementáció
Console.WriteLine(i.Nevem());
Console.ReadKey();
}
}
}
A program kimenete:
IMasik implementáció
IEgyik implementáció