Son zamanlar sıkça "dynamic" ve eski dostumuz "object" arasında ne fark olduğu sorusuyla karşılaşıyorum. İkisi arasında bir fark var mı? Bu sorunun yanıtı hem evet, hem hayır aslında. Eğer arka planda yapılan işleri bilmiyorsanız, evet, rahatlıkla object kullandığınız her yerde kullanabilirsiniz ve derleme-zamanında herhangi bir hata ile karşılaşmazsınız. Peki, bunun sizin için gerçek maliyeti nedir? Sanırım yazımın devamını okuyarak kararı sizin vermeniz en doğrusu.
Önceliği eski dostumuz "object"'te verirsem sanırım kimse alınmaz. object, hepinizin de bildiğini biliyorum ama, "System.Object"'e kısayoldan başka bir şey değil aslında ve C#'ın ilk sürümünden beri hayatımızda. C#'ta neredeyse her şeyin bir nesne olduğu ve object'den türediğini düşünürsek ne kadar güçlü olduğunu anlayabiliriz; neredeyse her değeri atayabiliriz.
Yazımın geri kalanında karşılaştırmayı örnek bir kod üzerinden yapmak daha iyi olacak sanırım. Aşağıda basit bir kod parçacığı göreceksiniz;
object nesne = 1;
if (nesne.GetType() == typeof(int)){
Console.WriteLine("Tabi ki türü int");
} else {
Console.WriteLine("Tüm makale hatalıymış :P");
}
Bu kod parçacığının çıktısını sorsam, eminim ki "Tüm makale hatalıymış :P" diyenleriniz olacaktır, ne de olsa "nesne int değil bir object olarak tanımlanmış"; ama gerçekte çıktı "Tabi ki türü int". Her ne kadar nesne tanımlaması sırasında object olarak belirlenmişte olsa çalışma-zamanında içerisine konulan değer bir int.
Bu örnekte nesne içerisinde her ne kadar bir int türünden veri yeralsa da, üzerinde bir int'e uygulayabileceğiniz toplama işlemi gibi basit bir işlemi yapmaya çalıştığınızda bakın neler oluyor;
object nesne = 1;
if (nesne.GetType() == typeof(int)){
Console.WriteLine("Tabi ki türü int");
} else {
Console.WriteLine("Tüm makale hatalıymış :P");
}
nesne = nesne + 1;
İlk örneğimiz sorunsuz olarak derlenirken, bu basit değişiklik sonrasında kodumuz derleme sırasında hata alacaktır ve derlemek isteğimizde öncelikle nesne'yi int türüne dönüştürmeliyiz;
object nesne = 1;
if (nesne.GetType() == typeof(int)){
Console.WriteLine("Tabi ki türü int");
} else {
Console.WriteLine("Tüm makale hatalıymış :P");
}
nesne = (int)nesne + 1;
Bu basit dönüşüm, derleyiciye ne yaptığımızı bildiğimizi belirtmenin bir yolu: nesne'm bir int ifadedir. Bu noktada derleyici için nesne'nin değeri bir object olmaktan çıkar. Tabi ki, önemle not düşmem gerekir ki, tür dönüşümünü yaparak derleme-zamanı hata alınmaması her şeyin %100 doğru olduğu anlamına gelmeyecektir. Bu duruma örnek vermek gerekirse, aşağıdaki kod parçacığında nesneyi string türüne harici olarak dönüştürme işlemi derleme-zamanında bir hataya neden olmayacak; fakat derlenen kod çalıştırıldığında çalışma-zamanı hata alınacaktır:
object nesne = 1;
if (nesne.GetType() == typeof(int)){
Console.WriteLine("Tabi ki türü int");
} else {
Console.WriteLine("Tüm makale hatalıymış :P");
}
nesne = (string)nesne + 1;
Derleyici, siz harici olarak belirtmediğiniz sürece, nesne'yi object türünden kabul etmekte ve üzerinden başka bir türe ait işlem yapmaya izin vermemekte; fakat kazayla içindeki değerden yukarıdaki örnekte olduğu gibi harici olarak farklı bir tür'e dönüştürülmesi çalışma-zamanı hataya neden olacaktır.
.Net 4.0'la sahne alan önemli yeniliklerden biri olan "dynamic", kabaca anlatmak gerekirse, harici olarak derleyiciye bu tür üzerinde derleme sırasında herhangi bir kontrol yapılmayacağını belirtir. Yapılacak olan işlemler çalışma-zamanındaki veriler doğrultusunda yorumlanarak yerine getirilir. İlk örneğin dynamic versiyonuda aşağıdaki örnekte de göreceğiniz gibi ilk kullanıma oldukça benzer:
dynamic nesne = 1;
if (nesne.GetType() == typeof(int)){
Console.WriteLine("Tabi ki türü int");
} else {
Console.WriteLine("Tüm makale hatalıymış :P");
}
Üstelik, ilk object örneğinden farklı olarak, aşağıdaki kod herhangi bir tür değişimine ihtiyaç duymaksızın hatasız şekilde derlenir;
dynamic nesne = 1;
if (nesne.GetType() == typeof(int)){
Console.WriteLine("Tabi ki türü int");
} else {
Console.WriteLine("Tüm makale hatalıymış :P");
}
nesne = nesne + 1;
Bunun sebebi, dynamic'i tanıtırken de belirttiğim gibi, derleme-zamanında tür üzerinden kontrol yapılmaması. İşte bu object ile dynamic arasındaki en önemli farktır. Nesnenin dynamic ile tanımlanmasıyla birlikte programcı derleyiciye bu nesne içindeki veri türünün ancak çalışma zamanında belli olabileceğini ve bu sebeple de derleme zamanında hata vermemesi gerektiğini belirtir. Sonuç olarak da, derleyici bu veri türü için yapılan işlemlere müdahale etmez. Aşağıdaki kod parçacığının son satırı bahsettiğim duruma basit bir örnek olacaktır:
dynamic nesne = 1;
if (nesne.GetType() == typeof(int)){
Console.WriteLine("Tabi ki türü int");
} else {
Console.WriteLine("Tüm makale hatalıymış :P");
}
nesne.VarolmayanBirMethod();
Bu kod parçacığı sizinde göreceğiniz gibi hatasız derlenecek; fakat çalışma zamanında nesne içerisinde VarolmayanBirMethod bulunamadığı için çalışma-zamanı hatası alınacaktır.
"Peki derleyici dynamic türler üzerinde derleme sırasında kontrol yapmıyorsa nasıl bir işlem yapıyor?"
dynamic tanımlanan türler üzerinde yapılan işlemler (örneğin method çağrıları) hakkında derleme zamanında analiz yapılır. Çağrılan metodun ismi, parametre sayısı, parametre türleri, bağlayıcı türü(c# nesnesi, python nesnesi, COM nesnesi) v.b. bilgiler çalışma-zamanında kullanılmak üzere saklanır. Çalışma-zamanında türün aldığı değer doğrultusunda bu bilgiler kullanılarak talep edilen işlemler gerçekleştirilir. Dolayısıyla eksik ve/veya hatalı bilgi verilmesi (olmayan bir metot adı, eksik parametre) derleme-zamanı değil çalışma-zamanı hataya neden olacaktır.
Yapılan bu çalışma-zamanı yorumlama işi tabi ki uygulamanıza ek bir yük getirecektir (işlemci zamanı ve hafıza kullanımı olarak), bu ek yükün hafifletilmesi anlamında gerekli önbellek işlemlerinin yapıldığını da not olarak düşmem gerekir. Bu sayede, örneğin bir döngü içerisinde yapılan bir dynamic çağrı da ilk defadan sonra yeniden bir yorumlama yapılmayarak önbellekte hazır bulunan kod parçacığı işletilir.
dynamic hakkında unutulmaması gereken önemli bir noktada, arka planda kullanılan Dinamik dil çalışma-zamanı kütüphanesinin (Dynamic Language Runtime - DLR) .Net için sadece C# diliyle yazılmış bir kütüphane olduğudur, aynı sizlerin yazdığı kütüphaneler gibi. Dolayısıyla da yukarıdaki örneklerdeki gibi kullanımlarda hızlı, okunur kod yazılmasını sağlamakla birlikte normalde yapılabilecek basit bir tür dönüşümünden öteye geçilerek arka planda sizin yerinize yapılan çağrılar nedeniyle kodun performansı düşecektir.
"BÜYÜK BİR GÜÇLE BİRLİKTE BÜYÜK SORUMLULUKTA GELMELİDİR"
C# 4.0 ile birlikte gelen önemli özelliklerde birisi olan "dynamic" temelde iki amaca hizmet vermesi için getirilmiştir;
- C# ve COM birlikte işlerliğinin kolaylaştırılması
- C# ve dinamik dillerin (Javascript, Python, Ruby v.b.) birlikte işlerliğinin sağlanması ve kolaylaştırılması
Bu amaçlar dışında kullanılabiliyor olmasına karşın; başta performans olmak üzere, derleme zamanı hataların fark edilememesi v.b. nedenlerle tavsiye edilmemektedir, sadece gerekli olduğunda ve çok dikkatli biçimde kullanılmalıdır.