Bir önceki makaleme gelen güzel yorumlar sonrası dynamic hakkında ikinci bir makale ile konuyu detaylandırmanın faydalı olacağını düşündüm.
C# 4.0'la birlikte gelen özellikleri inceleyenlerin dynamic hakkında düştüğü ortak bir yanılğı, dynamic'in CLR seviyesinde desteklendiğidir. Her ne kadar dynamic hayatımızda önemli bir değişikliğe neden olsa da, bu yanılgıya düşenler için basit kullanımlarda beklediklerinin aksine uygulamalarında performans kayıplarına neden olacaktır.
dynamic, CLR açısından bakıldığında, herhangi bir C# kütüphanesinden farklı değildir. Tabi ki microsoft bu kütüphanenin bizler tarafından daha kolay kullanılabilmesi amacıyla C# diline ekleme yapmış, derleyici desteği sağlamıştır.
Konuyu daha netleştirebilmek için bir önceki makalemde verdiğim aşağıdaki dynamic kod örneğini hatırlayalım:
1: class Program {
2: static void Main(string[] args) {
3: dynamic nesne = 1;
4:
5: if (nesne.GetType() == typeof(int)){
6: Console.WriteLine("Tabi ki türü int");
7: } else {
8: Console.WriteLine("Tüm makale hatalıymış :P");
9: }
10:
11: nesne = nesne + 1;
12: }
13: }
Bu örneğin derlenmesi sonrası oluşan kodu reflector ile incelersek karşımıza aşağıdaki gibi bir kod çıkacaktır:
1: internal class Program {
2: private static void Main(string[] args) {
3: object nesne = 1;
4: if (<ma IN>o__SiteContainer0.<>p__Site1 == null) {
5: <ma IN>o__SiteContainer0.<>p__Site1 = CallSite<func><calls ITE, object, bool>>.Create(
6: Binder.UnaryOperation(CSharpBinderFlags.None,
7: ExpressionType.IsTrue,
8: typeof(Program),
9: new CSharpArgumentInfo[] {
10: CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null)
11: }));
13: if (<ma IN>o__SiteContainer0.<>p__Site2 == null) {
14: <ma IN>o__SiteContainer0.<>p__Site2 = CallSite<func><calls ITE, object, Type, object>>.Create(
15: Binder.BinaryOperation(CSharpBinderFlags.None,
16: ExpressionType.Equal,
17: typeof(Program),
18: new CSharpArgumentInfo[] {
19: CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null),
20: CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.UseCompileTimeType, null)
21: }));
22: }
23: if (<ma IN>o__SiteContainer0.<>p__Site3 == null) {
24: <ma IN>o__SiteContainer0.<>p__Site3 = CallSite<func><calls ITE, object, object>>.Create(
25: Binder.InvokeMember(CSharpBinderFlags.None,
26: "GetType",
27: null,
28: typeof(Program),
29: new CSharpArgumentInfo[] {
30: CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null)
31: }));
32: }
33: if (<ma IN>o__SiteContainer0.<>p__Site1.Target.Invoke(<ma IN>o__SiteContainer0.<>p__Site1,
34: <ma IN>o__SiteContainer0.<>p__Site2.Target.Invoke(<ma IN>o__SiteContainer0.<>p__Site2,
35: <ma IN>o__SiteContainer0.<>p__Site3.Target.Invoke(
36: <ma IN>o__SiteContainer0.<>p__Site3, nesne),
37: typeof(int)))) {
38: Console.WriteLine("Tabi ki t\x00fcr\x00fc int");
39: }
40: else {
41: Console.WriteLine("T\x00fcm makale hatalıymış :P");
42: }
43:
44: if (<ma IN>o__SiteContainer0.<>p__Site4 == null) {
45: <ma IN>o__SiteContainer0.<>p__Site4 = CallSite<func><calls ITE, object, object int,>>.Create(
46: Binder.BinaryOperation(CSharpBinderFlags.None,
47: ExpressionType.Add, typeof(Program),
48: new CSharpArgumentInfo[] {
49: CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null),
50: CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.Constant | CSharpArgumentInfoFlags.UseCompileTimeType, null)
51: }));
52: }
53: nesne = <ma IN>o__SiteContainer0.<>p__Site4.Target.Invoke(<ma IN>o__SiteContainer0.<>p__Site4, nesne, 1);
54: }
55:
56: [CompilerGenerated]
57: private static class <ma IN>o__SiteContainer0 {
58: public static CallSite<func><calls ITE, object, bool>> <>p__Site1;
59: public static CallSite<func><calls ITE, object, Type, object>> <>p__Site2;
60: public static CallSite<func><calls ITE, object, object>> <>p__Site3;
61: public static CallSite<func><calls ITE, object, object int,>> <>p__Site4;
62: }
63: }
Tabi ki bu karşılaştırma hiç bir zaman dynamic kullanmayın demek değil; fakat doğru yerde kullanın demek ;)
"Peki dynamic kullanımı için doğru yer neresidir?"
.Net 4.0 DLR (Dynamic Language Runtime, Dinamik Dil Çalışma-Zamanı) ve birlikte gelen dynamic anahtar kelimesi, statik diller (C#, Visual Basic v.b.) ile dinamik diller (Python, Ruby v.b.) arasında bir köprü olmaktadır.
Üstelik bu köprü sadece Python ve Ruby dilleriyle de sınırlı olmayıp; Javascript, Silverlight, Ofis/COM ve diğer pek çoklarını da kapsamaktadır.
.Net 4.0 öncesinde dinamik diller ve COM ile iletişim kurmakta yaşadığımız pek çok zorluk DLR ile birlikte tarih olacak gibi görünüyor. Bu noktalardaki dynamic kullanımı gerek geliştirme süresini hızlandırmada, gerekse de kod okunurluğunu arttırmada önemli bir katma değer sağlayacaktır.
"Dinamil Dil Çalışma-Zamanı (DLR) nasıl çalışır?"
Yazımın başında da belirttiğim gibi CLR bakış açısıyla DLR sadece bir kütüphanedir; fakat hayatımızdan önemli bir yer tutacak bir kütüphane :)
Dinamik dil çalışma-zamanı hakkında daha önce de araştırma yaptıysanız aşağıdaki grafik size tanıdık gelecektir.
Statik dillerle dinamik diller arasında bir köprü olan DLR bu grafikte de görüldüğü gibi 4 ana parçadan oluşur:
Yukarıdaki bilgiler ışığında, yazdığınız bir dinamik kod DLR tarafından öncelikle daha önceden işlenip işlenmediğinin anlaşılması amacıyla önbellekte kontrol edilir. Eğer aynı işlem daha önce çağrıldıysa önbellekte yer alan temsilci (delegate) üzerinden hazırda bulunan adımlarla işlevini yerine getirir. Eğer dinamik kod ilk defa işleniyorsa ifade ağacı ilgili call site'a iletilerek arkaplanda yer alan bağlayıcı yardımıyla çalıştırılır ve sonraki kullanımlarda kullanılmak üzere bir temsilci atanarak önbelleğe alınır.
Yukarıda anlattıklarımdan sonra heyecanlanmamak mümkün değil bence. Şimdiye kadar işlemlerimizi statik olarak gerçekleştirdiğimiz C#, Visual Basic gibi dillere dinamik olarak çalışma-zamanında işlem yapabilme yeteneği eklenmesi kayda değer bir yenilik.
Fatih Boy fatih@enterprisecoding.com http://www.enterprisecoding.com http://twitter.com/fatihboy