Autor podstrony: Krzysztof Zajączkowski

Stronę tą wyświetlono już: 2135 razy

Interfejsy działają w pewnym stopni jak klasy abstrakcyjne w C++, jednakże interfejsy ograniczają się do deklaracji metod i właściwości, które klasa dziedzicząca po takim interfejsie musi obsłużyć. Oto prosty przykład interfejsu:

interface IPoint2D { double Length { get; set; } string ToString(); double X { get; set; } double Y { get; set; } }

Teraz, jeżeli w kodzie programu utworzę klasę dziedziczącą po interfejsie IPoint2D, to taka klasa musi obsłużyć wszystkie metody i właściwości, zadeklarowane w tymże interfejsie. Poniżej zamieszczam przykład implementacji dwóch interfejsów i dwóch klas po nich dziedziczących:

interface IPoint2D { double Length { get; set; } string ToString(); double X { get; set; } double Y { get; set; } } interface IPoint3D : IPoint2D { new double Length { get; set; } new string ToString(); double Z { get; set; } } // ########################### DEKLARACJA KLASY POINT@D ############################# public class Point2D : IPoint2D { // ####################### CHRONIONE POLA KLASY ################################# protected double x; protected double y; // ####################### KONSTRUKTORY KLASY ################################### public Point2D() // konstruktor zerujący { x = y = 0; } public Point2D(double x, double y) // konstruktor ustawiajacy { this.x = x; this.y = y; } public Point2D(Point2D p) // kosntruktor kopiujący { this.x = p.x; this.y = p.y; } // ######## WŁAŚCIWOŚCI KLASY ########## public double Y { get { return y; } set { y = value; } } public double X { get { return x; } set { x = value; } } public double Length { get { return Math.Sqrt(x * x + y * y); } // pobieranie długości wektora set // ustawianie długości wektora { if (x != 0 || y != 0) // gdy wektor nie jest zerowy to { double k = value / Length; x *= k; // skalowanie składowej x wektora y *= k; // skalowanie składowej y wektora } } } // ########### METODY ############# public override string ToString() // przeładowana metoda ToString klasy bazowej Object { return "Point2D x = " + x + "; y = " + y; } } // ############################## DEKLARACJA KLASY POINT3D ################################# public class Point3D : Point2D, IPoint3D // dziedziczy po Point2D { // ########################## CHRONIONE POLA KLASY ##################################### protected double z; // ########################## KONSTRUKTORY KLASY ####################################### public Point3D() : base() // wywołanie bezparametrowego kosntruktora klasy bazowej { z = 0; } public Point3D(double x, double y, double z) : base(x, y) // wywołanie ustawiającego konstruktora klasy bazowej { this.z = z; } public Point3D(Point3D p) // konstruktor kopiujący : base(p) // wywołanie kontruktora kopiującego klasy bazowej { z = p.z; } // ################# WŁAŚCIWOŚCI ############### public double Z { get { return z; } set { z = value; } } public new double Length // przysłanianie właściwości z klasy bazowej (oznacza to słowo kluczowe new) { get { return Math.Sqrt(x * x + y * y + z * z); } // pobieranie długości wektora set // ustawianie długości wektora { if (x != 0 || y != 0 || z != 0) { double k = value / Length; X *= k; Y *= k; z *= k; } } } // ################# METODY ################ public new string ToString() // przysłanianie metody z klasy bazowej (oznacza to słowo kluczowe new) { return "Point3D x = " + X + "; y = " + Y + "; z = " + z; } }

Przykład zastosowanie interfejsów do przechowywania różnych zmiennych w jednej tablicy:

namespace Klasy { class Program { static void Main(string[] args) { IPoint2D[] t = new IPoint2D[2]; t[0] = new Point2D(100, 200); t[1] = new Point3D(20, 30, 40); foreach (IPoint2D p in t) { if (p is Point3D) { Console.WriteLine(((Point3D)p).ToString()); } else { Console.WriteLine(p.ToString()); } } Console.ReadLine(); } } }

Wynik działania powyższego kodu:

Point2D x = 100; y = 200
Point3D x = 20; y = 30; z = 40

Nic nie stoi na przeszkodzie, aby utworzyć metodę klasy, która będzie przyjmowała jako argument dany interfejs. W takim przypadku każdy obiekt klasy, która dziedziczy po owym interfejsie będzie mógł zostać przekazany jako parametr takiej metody.