1. Giriş
Bir vaxtlar interfeyslər elə sərt idi ki, sanki özəl məktəbin nizamnaməsi: yalnız signaturalar, heç bir field, heç bir implementasiya, heç bir statik üzv! Amma .NET inkişaf edir, proqramlaşdırma dili isə canlı orqanizm kimidir: yeni çağırışlara cavab vermək üçün daim təkamül etməlidir.
Yeni C# versiyaları ilə interfeyslər yeni fəndlər öyrəndi. Ən nəzərəçarpanlardan biri — statik üzvlər interfeyslərdə. İndi interfeyslər statik metodlar, property-lər və event-lər saxlaya bilir. Yeni C# versiyalarında (C# 11-dən başlayaraq) hətta statik abstrakt metodlar elan etmək olur ki, bu da həmin interfeysi implement edən tiplərdən bu metodları mütləq yazmağı tələb edir.
Bu — proqramlaşdırmada böyük paradigma dəyişikliyidir, generic və obyekt yönümlü proqramlaşdırmaya yanaşmanı dəyişir.
Sadə dillə desək: interfeysin statik üzvü — bu "ümumi" üzvdür, ona interfeys tipinin özü (və ya implementasiya edən tip) vasitəsilə müraciət olunur, obyekt nümunəsi ilə yox.
Yaxın vaxta qədər yalnız class, struct və enum-lar statik metod və property-lərə sahib ola bilirdi, indi isə bu imkan interfeyslərə də gəldi.
Bu necə görünür? Sintaksis nümunəsi
public interface IMyMath
{
static int Add(int a, int b) => a + b; // Statik metod (default implementasiya)
static abstract int Multiply(int a, int b); // Implementasiya edən tipdə yazılmalıdır
}
- static — üzv tip səviyyəsində əlçatandır, nümunədə yox.
- static abstract — kontrakt "tələb edir" ki, implementasiya edən tipdə statik metod yazılsın.
- İndi interfeyslərdə (class-larda olduğu kimi) statik metodlar, property-lər və event-lər elan etmək olar. Həmçinin konstantlar da yaratmaq mümkündür. Amma interfeyslərdə hələ də nümunə field-ləri və ya statik field-lər (konstantlardan başqa) ola bilməz.
Statik üzvlərin interfeyslərdə əsas funksiyası — universal "əməliyyatlar" elan etməkdir. Məsələn, əgər səndə obyektlər kolleksiyası var və onların "müqayisəsini" çağırmaq istəyirsən, amma hansı tipin interfeysi implement etdiyini bilmirsən, bunu statik abstrakt üzvlərlə etmək mümkündür.
2. İnterfeysdə implementasiyalı statik metodlar
Bunun nəyə faydası var?
Klassik problem: sən yalnız "nümunə" metodları (məsələn, obyektlə nəsə etmək) yox, həm də "statik" metodları (məsələn, string-dən yeni obyekt yaratmaq və ya iki obyekti statik şəkildə müqayisə etmək) təsvir etmək istəyirsən. Əvvəllər bunu pattern-lərlə (Factory, Comparer, Helper) həll edirdik, indi isə bunu birbaşa interfeys vasitəsilə ifadə etmək olur.
Xüsusilə bu, Generics və müxtəlif tiplərlə işləyən alqoritmlər üçün vacibdir:
- Universal operatorların implementasiyası (məsələn, toplama, müqayisə).
- Generic kodun məhdudlaşdırılması: "Statik metod və ya operatoru olan istənilən tiplər..."
- Seriyalizasiya/deseriyalizasiya: kod yazılan anda tipi bilmədən string-dən obyekt yaratmaq lazım olanda.
İmplementasiyalı statik metodlar
C# 8-dən başlayaraq interfeyslərdə implementasiyalı statik metodlar yazmaq olar. Onlar class-dakı adi statik metodlara bənzəyir.
public interface IUtility
{
static void PrintHello()
{
Console.WriteLine("Salam interfeys-dən!");
}
}
Belə metodu belə çağırmaq olar: IUtility.PrintHello();
Bu, interfeysə məntiqi aid olan, amma konkret implementasiyaya aid olmayan köməkçi funksiyalar üçün rahatdır. Məsələn: tip üzrə ümumi statistika, fabrik metodları (CreateDefault), ümumi köməkçi yoxlamalar (məsələn, dəyərlərin düzgünlüyünü yoxlamaq).
Xüsusiyyət: interfeys statik üzvləri class-larda "override" olunmur
Əgər interfeysdə static void Method() { ... } elan etmisənsə, implementasiya edən class eyni signaturada statik metod yaza bilər — amma bu, override deyil! Sadəcə iki müstəqil metoddur — adları eyni olsa da, "virtual statik metod" deyil.
3. Statik abstrakt üzvlər
C# 11-dən başlayaraq interfeyslərdə static abstract metodlar elan etmək olur. Bu o deməkdir ki: "hər bir class və ya struct, bu interfeysi implement edirsə, həmin signaturada statik üzv yazmalıdır".
Nümunə:
public interface IParsable<T>
{
static abstract T Parse(string s);
}
Bu interfeysi implement edən istənilən tip statik metod Parse(string s) yazmalıdır.
Belə interfeysin class-da implementasiyası
public class Temperature : IParsable<Temperature>
{
public int Value { get; set; }
// Statik implementasiya!
public static Temperature Parse(string s)
{
var temp = new Temperature();
temp.Value = int.Parse(s);
return temp;
}
}
Bu necə işləyir?
Bu, generic kodda (Generics) xüsusilə maraqlıdır:
public static T ParseFromString<T>(string s) where T : IParsable<T>
{
return T.Parse(s);
}
// İstifadə:
var temp = ParseFromString<Temperature>("42");
İndi həqiqətən universal kod yazmaq olur ki, istənilən "statik" davranışlı tiplərlə işləyir!
4. İnterfeysdə statik üzvlər vs. class-da adi statik üzvlər
| Xüsusiyyət | Class-da statik üzv | İnterfeysdə statik üzv |
|---|---|---|
| İrsi olur | Yox | Yox, amma interfeys-kontrakt çərçivəsində implementasiya olunur |
| Implementasiya tələb edir | Yox | Yalnız static abstract olarsa |
| Generics-də istifadə olunur | Yox (C# 11-ə qədər) | Bəli (static abstract ilə) |
| Default implementasiya ola bilər | Bəli | Bəli |
| Override | Yox | Yox, sadəcə implementasiya mütləqdir |
| Çağırışda görünürlük | Tip adı ilə | İnterfeys tipi və ya implementasiya edən tip ilə |
7. Real həyatdan nümunələr
Gəlin baxaq, yeni imkanlarla kiçik tədris tətbiqimizi necə yaxşılaşdıra bilərik.
Bizdə "IPrintable" interfeysi olsun:
public interface IPrintable
{
void Print();
static void PrintAll(IEnumerable<IPrintable> items)
{
foreach (var item in items)
{
item.Print();
}
}
}
İndi rahatlıqla belə çağırmaq olar:
var documents = new List<IPrintable>
{
new Invoice { Number = "INV-001" },
new Receipt { Number = "RC-007" }
};
IPrintable.PrintAll(documents); // interfeysin statik metodu!
Belə arxitektura interfeysin bütün implementasiyaları üzərində "qrup əməliyyatları" üçün əladır.
Daha inkişaf etmiş nümunə: ədədi tiplərin generic toplanması
Bizdə belə interfeys olsun:
public interface IAddable<T>
{
static abstract T Add(T left, T right);
}
Tam ədədlər üçün implementasiya (wrapper class):
public struct MyInt : IAddable<MyInt>
{
public int Value { get; }
public MyInt(int val) => Value = val;
public static MyInt Add(MyInt left, MyInt right) => new MyInt(left.Value + right.Value);
}
Və nəhayət, iki T tipli ədədin toplanması üçün universal funksiya:
public static T Sum<T>(T a, T b) where T : IAddable<T>
{
return T.Add(a, b);
}
// İstifadə:
var x = new MyInt(5);
var y = new MyInt(6);
var z = Sum(x, y); // z.Value == 11
Bax, belə universallıq üçün interfeyslərdə statik üzvlər dəstəklənməyə başladı!
8. Tipik səhvlər və xüsusiyyətlər
Yeni fəndlərlə həyat həmişə nümunələrdəki kimi asan olmur. Budur, yeni başlayanları çaşdıra biləcək bir neçə məqam:
İnterfeys statik metodları implementasiya edən class tərəfindən "irsi olmur". Əgər interfeysdə static void Foo() elan etmisənsə, MyClass.Foo() və IMyInterface.Foo() — bunlar tamamilə fərqli iki metoddur.
Static abstract mütləq implementasiya olunmalıdır. Əgər unutdunsa — kompilyator xəbər verəcək ki, class interfeysi tam implementasiya etmir.
Generic constraints: statik abstrakt üzvlərdən istifadə üçün generic parametrlərdə interfeys ilə məhdudlaşdırmaq lazımdır (where T : IMyInterface).
Bütün alətlər hələ yeni imkanları tam dəstəkləmir. Məsələn, Rider, VS Code və ya köhnə Roslyn analizatorları bəzən interfeyslərdə static abstract-üzvləri düzgün göstərmir, əgər .NET versiyası C# 11+ dəstəkləmir.
Bunu extension-metodlarla qarışdırma: onlar ayrıca implementasiya olunur və statik üzvlər kimi işləmir.
GO TO FULL VERSION