CodeGym /Kurslar /C# SELF /Reflection-dən istifadə

Reflection-dən istifadə

C# SELF
Səviyyə, Dərs
Mövcuddur

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
Type
Əsas giriş — hər şey buradan başlayır
FieldInfo
Sahə haqqında informasiya
PropertyInfo
Property haqqında informasiya
MethodInfo
Metod haqqında informasiya
ConstructorInfo
Konstruktor haqqında informasiya
EventInfo
Hadisə haqqında informasiya
MemberInfo
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
GetFields(BindingFlags.Public | ...)
Digərlərinə görünən hər şey
Private sahələr
GetFields(BindingFlags.NonPublic | ...)
Daxili, gizli sahələr
Yalnız instance
BindingFlags.Instance
Yalnız non-static
Yalnız static
BindingFlags.Static
Yalnız static üzvlər
Hamısı bir yerdə
BindingFlags.Public | NonPublic | Instance | Static
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)
GetField, GetFields
FieldInfo
.GetValue(obj), .SetValue(obj, x)
Property (prop)
GetProperty, GetProperties
PropertyInfo
.GetValue(obj), .SetValue(obj, x)
Metod (method)
GetMethod, GetMethods
MethodInfo
.Invoke(obj, parametrlər)
Konstruktor
GetConstructor, GetConstructors
ConstructorInfo
.Invoke(parametrlər)

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ə.

2
Tapşırıq
C# SELF, səviyyə, dərs
Bağlanıb
Metodun refleksiya ilə çağırılması
Metodun refleksiya ilə çağırılması
Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION