C# Reflection: Çalışma Zamanında Kod Analizi ve Dinamik Programlama

Modern yazılım geliştirme, esnek ve dinamik çözümler üretebilme ihtiyacını beraberinde getirir. Uygulamalarımızda, hangi tipin veya metodun kullanılacağını derleme zamanında belirleyemediğimiz durumlar olabilir. İşte tam da bu noktada Reflection devreye girer. Reflection sayesinde; çalışma zamanında bir nesnenin yapısını inceleyebilir, dinamik olarak nesneler oluşturabilir ve metodları çağırabiliriz. Bu esneklik, özellikle plugin sistemleri, test frameworkleri ve dinamik yapılandırma gerektiren uygulamalarda büyük avantaj sağlar.

Reflection Nedir

Reflection, bir nesneye veya tipe çalışma anında (runtime) bakabilme ve onun hakkında bilgi alabilme veya onu kullanabilme özelliğidir. Yani: Normalde biz bir sınıfın özelliklerini yazarken biliriz:

Person p = new Person();
p.Name = "Fatih";

Ama reflection şunu der:

“Ben bu Person sınıfını yazarken bilmiyorum, ama program çalışırken öğrenmek ve ona göre işlem yapmak istiyorum.”

Gerçek hayattan örnek vericek olursak: Bir kargo kutusu düşünün üzerinde sadece barkod var ama içinde ne olduğunu bilmiyorsun. Elinde bir kutu tarayıcı (reflection) alıyorsun ve kutuyu tarıyorsun ve içindeki ürünün adı, içeriği, markası gibi bilgileri öğreniyorsun. Hatta istersen kutuyu açıp ürünle etkileşime bile geçebiliyorsun. İşte bu reflection hayattımızdaki tanımıdır.


System.Reflection

C#’ta reflection işlemleri, System.Reflection namespace’i üzerinden yapılır. Burada en çok kullanılan sınıfları ve fonksiyonlar şunlardır.

Type Sınıfı

Bir nesne ya da sınıf hakkında temel bilgi almak.

Type type = typeof(Person); // Türe göre Type type2 = obj.GetType(); // Nesneye göre

Özellikleri:

ÖzellikAçıklama
NameSınıf adı ("Person")
NamespaceBulunduğu namespace
IsClass, IsAbstract, IsInterfaceTür kontrolü
BaseTypeKalıtım ilişkisi
GetProperties()Property’leri döner
GetMethods()Metotları döner
GetFields()Field’ları döner
GetConstructors()Constructor’ları döner
GetCustomAttributes()Attribute’leri verir

PropertyInfo Sınıfı

PropertyInfo prop = type.GetProperty("Name"); object value = prop.GetValue(obj); prop.SetValue(obj, "Fatih");

Özellikleri

Yöntem / ÖzellikAçıklama
NameProperty adı
PropertyTypeTürü (örneğin string)
CanRead, CanWriteGet/set kullanılabilir mi
GetValue(object)Değerini alır
SetValue(object, value)Değerini ayarlar

MethodInfo Sınıfı

MethodInfo method = type.GetMethod("SayHello"); method.Invoke(obj, null);

Özellikleri:

Yöntem / ÖzellikAçıklama
NameMetot adı
ReturnTypeGeri dönüş tipi
GetParameters()Parametre listesini verir
Invoke(object, object[])Metodu çağırır

ConstructorInfo Sınıfı

ConstructorInfo ctor = type.GetConstructor(Type.EmptyTypes); object instance = ctor.Invoke(null);

FieldInfo Sınıfı

FieldInfo field = type.GetField("myField", BindingFlags.NonPublic | BindingFlags.Instance); field.SetValue(obj, 42);

Private alanlara erişmek için mutlaka BindingFlags kullan.


Activator

object obj = Activator.CreateInstance(typeof(Person));

Özellikleri:

YöntemAçıklama
CreateInstance(Type)Varsayılan constructor’la nesne oluşturur
CreateInstance(Type, args)Parametreli constructor’la nesne oluşturur

BindingFlags – Üyeleri Kontrol Et

Reflection ile erişimde neyi görmek istediğini belirtirsin.

SabitAçıklama
PublicPublic olanlar
NonPublicPrivate/internal olanlar
InstanceNesneye ait (non-static) üyeler
StaticStatic üyeler
DeclaredOnlyBase class’tan gelenler hariç sadece tanımlananlar
var methods = type.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);

Custom Attributes Okuma

var attr = method.GetCustomAttribute<LogAttribute>(); var allAttrs = method.GetCustomAttributes(); // Tüm attribute'ler

Attribute varsa null dönmez, yoksa null döner.


Örnek Tip Bilgilerinin Elde Edilmesi


public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }

    public void Greet()
    {
        Console.WriteLine($"Merhaba, ben {Name} ve {Age} yaşındayım.");
    }
}

class Program
{
    static void Main()
    {
        // Person tipinin bilgilerini elde etme
        Type personType = typeof(Person);
        Console.WriteLine("Sınıf Adı: " + personType.Name);

        Console.WriteLine("\nMetodlar:");
        foreach (MethodInfo method in personType.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly))
        {
            Console.WriteLine("- " + method.Name);
        }

        Console.WriteLine("\nÖzellikler:");
        foreach (PropertyInfo property in personType.GetProperties())
        {
            Console.WriteLine("- " + property.Name);
        }
    }
}

Örnek Dinamik Nesne Oluşturma ve Metod Çağırma

class Program
{
    static void Main()
    {
        // Person tipinin bilgilerini elde etme
        Type personType = typeof(Person);

        // Çalışma zamanında Person nesnesi oluşturma
        object personInstance = Activator.CreateInstance(personType);

        // Özelliklere değer atama
        PropertyInfo nameProp = personType.GetProperty("Name");
        PropertyInfo ageProp  = personType.GetProperty("Age");
        nameProp.SetValue(personInstance, "Reflection Ali");
        ageProp.SetValue(personInstance, 32);

        // Greet metodunu dinamik olarak çağırma
        MethodInfo greetMethod = personType.GetMethod("Greet");
        greetMethod.Invoke(personInstance, null);
    }
}

Örnek Private Üyeler Üzerinde İşlem Yapma

public class Secret
{
    private string secretMessage = "Bu gizli mesaj!";

    private void RevealSecret()
    {
        Console.WriteLine("Sır: " + secretMessage);
    }
}

class Program
{
    static void Main()
    {
        Type secretType = typeof(Secret);
        object secretInstance = Activator.CreateInstance(secretType);

        // Private alanı elde etme
        FieldInfo field = secretType.GetField("secretMessage", BindingFlags.NonPublic | BindingFlags.Instance);
        Console.WriteLine("Private Alan Değeri: " + field.GetValue(secretInstance));

        // Private metodu çağırma
        MethodInfo method = secretType.GetMethod("RevealSecret", BindingFlags.NonPublic | BindingFlags.Instance);
        method.Invoke(secretInstance, null);
    }
}