1. Giriş
C#-da hər hansı bir class (və ya struct) üzvlər toplusudur. Onlara daxildir:
- Fields (sahələr): məlumatları saxlayan dəyişənlər.
- Properties (xassələr): get/set ilə olan “aqil” qablaşdırıcılar.
- Methods (metodlar): funksionallıq.
- Constructors (konstrukturlar): nümunə yaratma üsulları.
- Events (hadisələr): nəşr/abunə mexanizmi daha rahat.
Təsəvvür edin ki, əlinizdə sehrli bir lupa var və onunla hər hansı tipin içini görə, onun tərkibini öyrənə və hətta onu dəyişdirə bilərsiniz. Bu, elə reflection-dir.
Namespace və reflection-in əsas tipləri
Başlamazdan əvvəl namespace-i əlavə etməyi unutmayın:
using System.Reflection;
Əsas klasslar və interfeyslər:
| Class/interfeys | Təsvir |
|---|---|
|
Əsas giriş — hər şey buradan başlayır |
|
Sahə haqqında informasiya |
|
Property haqqında informasiya |
|
Metod haqqında informasiya |
|
Konstruktor haqqında informasiya |
|
Hadisə haqqında informasiya |
|
Yuxarıdakılar üçün ümumi “validir” |
2. Reflection vasitəsilə tipin üzvlərini əldə etmək
Sahələri və properties-i əldə etmək
Nümunə: sahələrin və properties-in siyahısı
Tutaq ki, belə bir class var:
public class Person
{
public string Name { get; set; }
public int Age;
private string Secret = "Sekretnoye slovo";
}
Sahələri əldə etmək:
Type personType = typeof(Person);
FieldInfo[] fields = personType.GetFields(
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
foreach (var field in fields)
{
Console.WriteLine($"Sahə: {field.Name}, Tip: {field.FieldType.Name}, İcazə: {field.Attributes}");
}
Properties-i əldə etmək:
PropertyInfo[] properties = personType.GetProperties(
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
foreach (var property in properties)
{
Console.WriteLine($"Property: {property.Name}, Tip: {property.PropertyType.Name}");
}
İzahedici qeydlər
- BindingFlags — hansı üzvlərin axtarılacağını deyən “flaq”lar toplusudur (public/private, instance/static və s.).
- Sahələr və properties fərqlidir: field — sadə data parçası, property isə arxada get/set metodları olan qatdır.
Metodları əldə etmək
MethodInfo[] methods = personType.GetMethods(
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
foreach (var method in methods)
{
Console.WriteLine($"Metod: {method.Name}");
}
Çox metod çıxdığına təəccüblənəcəksiniz. Orada properties-in getter/setter-ləri və object-dən gələn xidmət metodları da olacaq!
Faydalı filter: yalnız sizin “aydın” metodlarınızı almaq üçün adı və ya atributu üzrə filtr əlavə edə bilərsiniz.
Hansı BindingFlags ilə nə axtarmaq
| Nə axtarırıq | Nümunə çağırış | Təsvir |
|---|---|---|
| Public sahələr | |
Digərlərinə görünən hər şey |
| Private sahələr | |
Daxili, gizli sahələr |
| Yalnız instance | |
Yalnız non-static |
| Yalnız static | |
Yalnız static üzvlər |
| Hamısı bir yerdə | |
Tam siyahı |
3. Tipin dinamik nümunəsinin yaradılması
Niyə bu faydalıdır?
Compile zamanında tipin dəqiq növünü bilmədən obyekt yaratmaq olar.
Sade üsul — Activator.CreateInstance
// Type-ı hər hansı üsulla alırıq, məsələn:
Type myType = typeof(Person);
// Obyekti yaradırıq:
object obj = Activator.CreateInstance(myType);
// İndi obj — Person nümunəsidir, amma kimi object
Əgər class-da parameter-siz konstruktor yoxdursa, parametrlər ötürə bilərsiniz:
public class Animal
{
public string Name { get; }
public Animal(string name) { Name = name; }
}
// ...
Type animalType = typeof(Animal);
object dog = Activator.CreateInstance(animalType, "Sharik");
Vacib!
Console.WriteLine(dog.GetType().Name); // Animal
Daha özəl üsul — ConstructorInfo
ConstructorInfo ctor = animalType.GetConstructor(new Type[] { typeof(string) });
object dog = ctor.Invoke(new object[] { "Sharik" });
Real həyatda adətən Activator istifadə olunur, amma bəzən dəqiq parametrlər və ya private konstruktorlarla işləmək lazım gəlir — o zaman ConstructorInfo köməyə gəlir.
4. Adla sahə və property-ə çıxış
Sahəni almaq və dəyişdirmək
Person p = new Person();
Type t = p.GetType();
FieldInfo field = t.GetField("Age");
field.SetValue(p, 42);
Console.WriteLine(field.GetValue(p)); // 42
Private sahələrlə işləmə:
FieldInfo secret = t.GetField("Secret", BindingFlags.NonPublic | BindingFlags.Instance);
if (secret != null)
{
secret.SetValue(p, "Oj, sekret raskryt");
Console.WriteLine(secret.GetValue(p));
}
else
{
Console.WriteLine("Secret sahəsi tapılmadı");
}
Diqqət! Private sahələrə çıxışı sui-istifadə etməyin — bu encapsulation-ı pozmaqdır və potensial səhvlərə yol aça bilər.
Property-ni almaq və dəyişdirmək
PropertyInfo pi = t.GetProperty("Name");
pi.SetValue(p, "Vasya");
Console.WriteLine(pi.GetValue(p)); // Vasya
Property-lər sahə deyil, arxada get/set metodları olan funksiyalardır.
Niyə bəzən işləmirsə?
Əgər field və ya property private-dirsə, mütləq uyğun BindingFlags təyin edin (məsələn, NonPublic). Əgər property-də setteri yoxdursa, reflection ilə ona heç nə yazmaq alınmayacaq — bu qayda işləyir.
5. Adla metodların çağırılması
Parametrsiz sadə metodun çağırılması
public class Greeter
{
public void SayHello()
{
Console.WriteLine("Privet!");
}
}
Greeter g = new Greeter();
Type t = g.GetType();
MethodInfo mi = t.GetMethod("SayHello");
mi.Invoke(g, null); // Privet!
Parametrlərlə metodun çağırılması
public class MathOp
{
public int Add(int x, int y) => x + y;
}
MathOp calc = new MathOp();
Type t = calc.GetType();
MethodInfo mi = t.GetMethod("Add");
object result = mi.Invoke(calc, new object[] { 7, 5 });
Console.WriteLine(result); // 12
Əgər metod static-disə, Invoke-un birinci arqumenti kimi null verin.
Overload-larla işləmək
MethodInfo mi = t.GetMethod(
"Add",
new Type[] { typeof(int), typeof(int) }
);
Yaxud əl ilə iterate edib filtr tətbiq edin:
foreach(var method in t.GetMethods()) {
if (method.Name == "Add" && method.GetParameters().Length == 2)
{
// ... bizim metod!
}
}
6. Faydalı nüanslar
Tipi analiz etmək üçün əsas üzvlər, metodlar və property-lər
| Class üzvü | İnfo almaq üçün metod | Nəticənin klassı | Dəyəri necə oxumaq/dəyişdirmək |
|---|---|---|---|
| Sahə (field) | |
|
|
| Property (prop) | |
|
|
| Metod (method) | |
|
|
| Konstruktor | |
|
|
Bütün bunlar real həyatda nəyə lazımdır?
- ORM-framework-lərdə (məsələn, Entity Framework modellərinizdən SQL sorğuları qurur).
- Serializer və parser sistemlərində (məsələn, JSON-serializerlər).
- Ümumi kitabxanalar üçün logging, testing, UI generator-larda.
- Müsahibələrdə — tez-tez "ümumi obyekt copy edici necə yazılar?" kimi suallar verirlər.
- Plugin yazmaq üçün, proqramınız başqa insanların yazdığı kodu yükləyib çağıranda.
Əgər indi bu sizə hacker-filmlərinin sehrinə oxşayırsa da, inanın — gələcəkdə işə yarayacaq!
7. Tipik səhvlər və xüsusiyyətlər
İnkişafçılar çox vaxt BindingFlags-ı qarışdırırlar — private sahələri görmürlər və ya əksinə çoxlu metod alırlar. Həmişə flaq kombinasiyasını yoxlayın: private sahələr üçün NonPublic, static üçün Static və s. istifadə edin.
Invoke vasitəsilə metod çağırarkən arqumentləri elan edildiyi ardıcıllıqda və tipdə verin. Yanlış ardıcıllıq/tip TargetParameterCountException və ya ArgumentException-a gətirib çıxarar. Return dəyəri object kimi gəlir — uyğun tipə cast etməyi (və ya pattern matching) unutmayın.
Performansı unutmamaq lazımdır: reflection birbaşa çağırışlardan yavaşdır. Hot path-lərdə tapılan Type/MethodInfo/PropertyInfo-ları cache edin və ya əvvəlcədən delegate-lər yaradın.
Tez-tez get_PropertyName və set_PropertyName kimi xidmət metodlarına rast gələcəksiniz. Bunlar property üçün access metodlarıdır — onları əl ilə yazmağa ehtiyac yoxdur.
Əgər private sahə və ya property-ni dəyişdirirsinizsə — encapsulation-ı pozursunuz. Yanlış istifadə çətin aşkarlanan səhvlərə səbəb ola bilər. Ustadınız Ben-in dediyi kimi: “Böyük güclə böyük məsuliyyət gəlir” — ehtiyatla istifadə edin, xüsusən kitabxana layihələrində.
GO TO FULL VERSION