.NET Custom Attribute’ler
Bu yazıda Microsoft .NET Framework’ün sunduğu en yenilikçi özelliklerden birini irdelemeye çalışacağım: attribute’ler. Attribute’ler, kod yapılarımıza bildirimsel olarak açıklama eklememize ve böylece özel özellikleri etkinleştirmemize olanak tanır. Attribute’ler, bilgilerin tanımlanmasına ve hemen hemen her Metadata tablosu girişine(method, property, class , vb.) uygulanmasına olanak tanır. Bu genişletilebilir Metadata bilgisi, kodun çalışma biçimini dinamik olarak değiştirmek için runtime’da ele alınır. Çeşitli .NET Framework teknolojilerini (Windows Forms, WPF, WCF, vb.) kullandıkça bunların hepsinin attribute’lerden yararlandığını ve geliştiricilerin kod içinde niyetlerini çok kolay bir şekilde ifade etmelerine olanak tanıdığını göreceksiniz.Bundan dolayı herhangi bir .NET Framework geliştiricisinin attribute’lere ilişkin sağlam bir bilgiye sahip olması gerekmektedir.
.NET’te custom attribute (özel nitelik), bir tür veya tür üyeleri(method, property, class, vb.) üzerinde belirli bir davranışı veya özelliği tanımlar. .NET uygulamalarında veri veya davranışın ek bilgisini sağlamak için kullanılır.
Attribute, Compiler, CLR ve Metadata İlişkisi
Attribute’ler public, private, protected , static gibi bütün tiplere ve tip elemanların uygulanabilir. Çünkü compiler kodun içerisinde bir attribute tanımı gördüğü zaman o attribute için Metadata dosyasının tanım tablolarına gerekli bilgiyi kaydeder. Bu yüzden CLR desteği veren bütün compiler’lar atrribute’ler için gerekli yapılandırmayı içerir. Çoğu attribute’ün compiler için bir anlamı yoktur. Compiler sadece gerekli çıktıları Metadata dosyasına yazar. Gerisi CLR’in işidir ve kodu istediği gibi yönetir.
.NET Framework Class Library (FCL) kelimenin tam anlamıyla yüzlerce atrribute içermektedir. Bulardan bazıları şöyledir.
- DllImport: Bu attribute ugulandığı metotun içerisinde yönetilemeyen(unmanaged) bir modülden gelen bazı metodların olduğu bilgisinini CLR’a bildirir. Yani CLR bu DlImport attribute’nü gördüğü zaman burada yönetilemeyen bir kodun olduğunu anlayacaktır.
- Serializable: Bu attribute bir tipe uygulandığı zaman, bu tip ile ilgili serialize ve deserialize işlemlerinin yapılabilidğini gösterir.
- AssemblyVersion: Bu attribute bir assembly’e uygulanarak versiyon numarası set edilir.
- Flags: Bu attribute bir enumarated tipine uygulandığı zaman, bu tipin bit flag olarak kullanılabileceğini bildirir.
Ya da web veya web api uygulamalarında Controller sınıflarında uyguladığımız “HttpPost”, “HttpGet”, “Authorize”, “Route”, “RoutePrefix” gibi. Veya ViewModel’lerde validasyon kontrolu için kullanılan “Required”, “DisplayName”, “StringLength” vb. attribute’ler örnek gösterilebilir.
Yukarıdaki örnekler gibi yüzlerce attribute Framework Class Library(FCL)’nin içinde mevcut ve kullanılmaktadır. C# sadece CLS desteği olan attribute’lerin oluşturulmasına izin verir. Dolayısıyla oluşturulan bütün attribute sınıfları “System.Attribute” sınıfından türetilir.
Attribute Kullanımı
Peki bu attribute’leri nasıl diğer tipler ve elemanlar ile ilişkilendirilecek? C# attribute’lerin kaynak kodta sadece assembly, module, class, struct, interface, delegate, field, metot, metot parametresi, metot return değeri, event, property ve generic tip parametresi alanlarına tanımlanmasına izin verir. Aşağıdaki C# kodunda bütün tip ve tip elemanlarına nasıl eklendikleri gösterilmektedir.
using System;
[assembly: SomeAttr] // assembly'e uygulama
[module: SomeAttr] // module'e uygulama
[type: SomeAttr] // tipe uygulama
internal sealed class SomeType<[typevar: SomeAttr] T> { // generic tip parametreye uygulama
[field: SomeAttr] // field'e uygulama
public Int32 SomeField = 0;
[return: SomeAttr] // return degerine uygulama
[method: SomeAttr] // metota uygulama
public Int32 SomeMethod( [param: SomeAttr] Int32 SomeParam) // parametreye uygulama
{
return SomeParam;
}
[property: SomeAttr] // property'ye uygulama
public String SomeProp
{
[method: SomeAttr] // get accessor metotuna uygulama
get { return null; }
}
[event: SomeAttr] // event'a uygulama
[field: SomeAttr] // compiler-generated field'e uygulama
[method: SomeAttr] // compiler-generated ekleme & çıkarma metotlarına uygulama
public event EventHandler SomeEvent;
}
Aynı şekilde bir hedefe birden fazla attribute uygulanabilir. Eğer attribute’ler parametre almıyorsa tek köşeli parantez kullanılarak ve virgül ile ayrılarak tanımlanabilir. Aşağıdaki tanımların hepsi geçerlidir.
[Serializable][Flags]
[Serializable, Flags]
[FlagsAttribute, SerializableAttribute]
[FlagsAttribute()][Serializable()]
public class SomeType {
}
Custom Attribute Sınıfı Oluşturma
C#’ta bir custom attribute oluştururken sınıfın “System.Attribute” sınıfından türetilmelidir. Bu sayede custom attribute “System.Attribute” sınıfının davranışını ve özelliklerini kazanmış olur.
using System;
public class CustomAttribute : Attribute
{
// Özellikler, constructor'lar ve gerekirse metodlar burada tanımlanır.
// Custom attribute'ün davranışını belirleyen kodlar bu sınıfta yer alır.
public string Name { get; set; }
public int Age { get; set; }
public CustomAttribute(string name, int age)
{
Name = name;
Age = age;
}
}
Custom Attribute Sınıfını Kısıtlamak
Custom attribute’ün kullanıldığı yerde bazı kısıtlamalar getirilebilir. Örneğin, attribute’ün sadece sınıflarda veya metotlarda kullanılmasını istenebilir.
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class CustomAttribute : Attribute
{
// ...
}
Custom Attribute Sınıfını Çağırmak
Oluşturulan custom attribute’ü kullanmak için “[attributeName]” söz dizimini kullanmak yeterli olacaktır.
[Custom("John Doe", 30)]
public class MyClass
{
// ...
}
Custom Attribute Sınıfına Runtime’da Erişmek
Custom attribute’ün bilgilerine çalışma zamanında erişmek için Reflection mekanizmasını kullanılabilir. Örneğin, bir türün üzerinde uygulanan custom attribute’ün özelliklerine erişebilir veya bu attribute’ü kullanan türleri tarama gibi işlemleri gerçekleştirebilir.
Type type = typeof(MyClass);
CustomAttribute attribute = (CustomAttribute)Attribute.GetCustomAttribute(type, typeof(CustomAttribute));
if (attribute != null)
{
string name = attribute.Name;
int age = attribute.Age;
// ...
}
Custom attribute’ler, .NET uygulamalarında veri ve davranışın daha fazla Metadata ile donatılmasını sağlar ve Reflection gibi araçlarla bu bilgilere erişerek dinamik işlemler gerçekleştirmenize olanak tanır.
Custom attribute’lar, kodun daha esnek ve okunabilir olmasını sağlar. Reflection mekanizmasıyla çalışma zamanında attribute bilgilerine erişebilir ve bu bilgilere göre dinamik davranışlar sergileyebiliriz. Örneğin, attribute’ları kullanarak derleme zamanında belirli türleri veya tür üyelerini otomatik olarak tarama veya belirli işlemler yapma gibi senaryoları gerçekleştirebiliriz.
Yararlanılan kaynaklar:
Microsoft CLR via C# Fourth Edition kitabı.