Reflection ve attribute
Reflection ve özel attribute'larla komut işleme yazarsın.
Reflection ve attribute
İkinci derste komut tek başınaydı. Şimdi komutları öznitelik ile işaretleyip reflection ile keşfedeceğiz. [Command("hello")] özniteliği bir sınıfa ad verir; Assembly.GetExecutingAssembly().GetTypes() tüm türleri tarar; t.GetCustomAttribute<CommandAttribute>() özniteliği okur.
Sonuç: yeni bir komut eklemek için yalnızca [Command("ad")] ile işaretli yeni bir sınıf yazarsın. Main'i değiştirmezsin; reflection komutu otomatik bulur. Bu, açık-kapalı ilkesinin güçlü bir uygulamasıdır.
Komut özniteliği
CommandAttribute sınıfı Attribute'tan türetilir ve bir Name özelliği taşır. Kullanım: [Command("hello")]. Parantez içindeki değer kurucuya aktarılır. Öznitelik, sınıfa derleme zamanında ek meta veri katar; çalışma zamanında reflection ile okunur.
Önemli: AttributeUsage ile özniteliğin yalnızca sınıflara uygulanabilmesini kısıtlayabilirsin. Şimdilik varsayılan kullanım yeterli; ileride bu kısıtı ekleyebilirsin.
Uygulama Komutları reflection ile keşfet
Bir CommandAttribute : Attribute sınıfı tanımla; kurucudan string name alıp Name özelliğine atsın. HelloCommand sınıfının üzerine [Command("hello")] ekle. Main'de Assembly.GetExecutingAssembly().GetTypes() ile tüm türleri tara; her tür için t.GetCustomAttribute<CommandAttribute>() çağır. Özniteliği olan ve ICommand'ı uygulayan türleri bir Dictionary<string, Type>'a ekle. commands["hello"] ile türü al, Activator.CreateInstance ile örnekle, (ICommand) türüne çevir ve await cmd.ExecuteAsync() sonucunu yazdır.
Örnek çözümü göster
Attribute { public string Name { get; } public CommandAttribute(string name) => Name = name; } yaz. [Command("hello")] ile HelloCommand'ı işaretle. Main'de: var commands = new Dictionary<string, Type>(); foreach (var t in Assembly.GetExecutingAssembly().GetTypes()) { var attr = t.GetCustomAttribute<CommandAttribute>(); if (attr != null && typeof(ICommand).IsAssignableFrom(t)) commands[attr.Name] = t; } var type = commands["hello"]; var cmd = (ICommand)Activator.CreateInstance(type); Console.WriteLine(await cmd.ExecuteAsync());
Örnek çözüm:
using System;
using System.Threading.Tasks;
using System.Reflection;
using System.Collections.Generic;
[Command("hello")]
class HelloCommand : ICommand
{
public async Task<string> ExecuteAsync()
{
await Task.CompletedTask;
return "Merhaba";
}
}
class CommandAttribute : Attribute
{
public string Name { get; }
public CommandAttribute(string name) => Name = name;
}
interface ICommand
{
Task<string> ExecuteAsync();
}
class Program
{
static async Task Main()
{
var commands = new Dictionary<string, Type>();
foreach (var t in Assembly.GetExecutingAssembly().GetTypes())
{
var attr = t.GetCustomAttribute<CommandAttribute>();
if (attr != null && typeof(ICommand).IsAssignableFrom(t))
commands[attr.Name] = t;
}
var type = commands["hello"];
var cmd = (ICommand)Activator.CreateInstance(type);
Console.WriteLine(await cmd.ExecuteAsync());
}
}
Kendini test et
-
Reflection terimlerini eşleştir
- [Command("hello")]
- Sınıfı adıyla işaretler
- GetTypes()
- Tüm türleri tarar
- GetCustomAttribute<T>
- Özniteliği okur
- Activator.CreateInstance
- Türü örnekler
-
Öznitelik kullanımını tamamla
[Command("____")] class HelloCommand : ICommand { ... }Cevabı göster
[Command("hello")] class HelloCommand : ICommand { ... } -
Reflection ile komut keşfi ne kazandırır?
- Daha hızlı çalışma
- Daha az kod yazma genel olarak
- Statik tip güvenliği
- Yeni komut eklemek Main'i değiştirmez
Cevabı göster
Yeni komut eklemek Main'i değiştirmez — Doğru. Reflection yeni komutu otomatik bulur; Main sabit kalır.