27 Aralık 2010 Pazartesi

Using diğer bir deyişle Try-Finally

Bu yazımızda using ifadesi nedir, ne değildir, ne yapar onu inceleyeceğim... Yine daha önce olduğu gibi basit bir kod yazarak konunun daha anlaşılabilir olmasını istiyorum.

using System.Data;

namespace Using_TryFinally
{
    class Deneme
    {
        static void Main()
        {
            using (DataTable dt = new DataTable())
            { 
            
            }
        }
    }
}


şeklinde hiçbir şey yapmayan bir kodumuz olsun. Bu kodu Visual Studio (VS) ile konsol uygulaması olarak derlediğiniz zaman ortaya çıkan exe'nin kodunu .NET Framework IL Disassembler (IL DASM) açıyoruz. Bu şekilde aslında arka planda neler oluyor, kodumuz ne hale geliyor onu görmüş oluyoruz. Şimdi VS'nin bizim kodumuzu dönüştürdüğü kodu bir inceleyelim:

.method private hidebysig static void  Main() cil managed
{
  .entrypoint
  // Code size       29 (0x1d)
  .maxstack  2
  .locals init ([0] class [System.Data]System.Data.DataTable dt,
           [1] bool CS$4$0000)
  IL_0000:  nop
  IL_0001:  newobj     instance void [System.Data]System.Data.DataTable::.ctor()
  IL_0006:  stloc.0
  .try
  {
    IL_0007:  nop
    IL_0008:  nop
    IL_0009:  leave.s    IL_001b
  }  // end .try
  finally
  {
    IL_000b:  ldloc.0
    IL_000c:  ldnull
    IL_000d:  ceq
    IL_000f:  stloc.1
    IL_0010:  ldloc.1
    IL_0011:  brtrue.s   IL_001a
    IL_0013:  ldloc.0
    IL_0014:  callvirt   instance void [mscorlib]System.IDisposable::Dispose()
    IL_0019:  nop
    IL_001a:  endfinally
  }  // end handler
  IL_001b:  nop
  IL_001c:  ret
} // end of method Deneme::Main


kod biraz karışık görünüyor olabilirama adım adım incelersek o kadar da karışık bir şey yapmadığını görüyoruz. İlk başta IL_0001 numaralı satırda DataTable objemizin constructor'ı çağırılıyor ve bir altındaki satırda oluşan obje dt isimli değişkenimize aktarılıyor. Daha sonra ise bir try-finally bloğu açılıyor. Biz using ifadesinin içerisine hiçbir şey yazmadığımız için try bloğunun içerisinde hiçbir şey yapılmadığını görüyoruz. Finally bloğunda ise bir şeyler oluyor. Orayı incelediğimizde ise ilk başta yaratılan objemizin null olup olmadığının kontrol edildiğini görüyoruz. Eğer null değilse objemizin Dispose() methodunun çağırıldığını görüyoruz.

Peki biz bu kodu using ifadesini kullanmadan yazmaya kalkarsak ne olur? VB aynı kodunu oluşturur mu onu deneyelim şimdi de. C# kodumuz şöyle olmalı:

using System.Data;

namespace Using_TryFinally
{
    class Deneme
    {
        static void Main()
        {
            DataTable dt = new DataTable();

            try
            {

            }
            finally
            {
                if (dt != null)
                    dt.Dispose();
            }
        }
    }
}


bu kodu derledikten sonra ortaya çıkan .exe'ye IL DASM ile bakıyoruz.

.method private hidebysig static void  Main() cil managed
{
  .entrypoint
  // Code size       31 (0x1f)
  .maxstack  2
  .locals init ([0] class [System.Data]System.Data.DataTable dt,
           [1] bool CS$4$0000)
  IL_0000:  nop
  IL_0001:  newobj     instance void [System.Data]System.Data.DataTable::.ctor()
  IL_0006:  stloc.0
  .try
  {
    IL_0007:  nop
    IL_0008:  nop
    IL_0009:  leave.s    IL_001d
  }  // end .try
  finally
  {
    IL_000b:  nop
    IL_000c:  ldloc.0
    IL_000d:  ldnull
    IL_000e:  ceq
    IL_0010:  stloc.1
    IL_0011:  ldloc.1
    IL_0012:  brtrue.s   IL_001b
    IL_0014:  ldloc.0
    IL_0015:  callvirt   instance void [System]System.ComponentModel.MarshalByValueComponent::Dispose()
    IL_001a:  nop
    IL_001b:  nop
    IL_001c:  endfinally
  }  // end handler
  IL_001d:  nop
  IL_001e:  ret
} // end of method Deneme::Main


iki tane fazla üretilen nop komutundan (IL_000b ve IL_001a satırlarında) başka farklılık olmadığını görüyoruz. Nop komutu da aslında bir işlem olmadığından dolayı aslında üretilen iki kodun da birbiri ile aynı olduğunu görüyoruz.

Using ifadesi ile Try-finally bloğu bu şekilde kullanıldığında birbirleriyle tam olarak aynı işlemi yaparlar. Hangisini kullanmak isterseniz kullanabilirsiniz buradan o sonuç çıkıyor. Benim tavsiyem kodun okunabilirliği açısından using kullanmak olacak...

23 Aralık 2010 Perşembe

Windows Server 2008 Cluster With Virtual PC

Merhaba,

bu yazıma başlamadan önce dün benimle birlikte yazmaya başlayan iş arkadaşım,can dostum güzel insan Ogün'e hoşgeldin demek istiyorum.Aslında bu yazıyı aceleye getirip şuan yazmamın da sebebi bu :) Bu yüzden fazla ayrıntıya girmeyeceğin zaten bu konuyla ilgili birçok güzel kaynak internette bulunmakta.Bunlardan bir kaçının linkini vereyim belki bu yazıyı okumayı çok istemiyorsunuzdur :)

ÇözümPark'tan Alper Özdemir'in yazısı ve yine ÇözümPark'tan Serhat Akıncı'nın yazıları:

http://www.cozumpark.com/blogs/windows_server/archive/2010/01/17/windows-server-2008-cluster-mimarisi.aspx

http://www.serhatakinci.com/index.php/tag/windows-server-2008-cluster

Gelelim benim bu konuda söylemek istediklerime.Bu işlerde aşırı çaylak bir eleman olarak takıldığım birçok konu oldu kurulum sırasında yada her zaman olduğu gibi ince ayrıntılar.Mesela ben sanal makinalarla 2 node'lu bir cluster yapısı kurmayı amaçlıyordum böyle örneklere vardı fakat windows 7 üzerinde virtual pc kullanarak yapılan bir örnek bulamadım ve haliyle hep sorunlar ve ince detayları bilmemekten kaynaklanan küçük problemler...

Neyse lafı çok uzatmıcam ve bu konuda cluster şudur bu budur gibi açıklamalara girmeyeceğim çünkü internette bir sürü kaynak var.Gelelim benim başarılı olduğum sistem ve kaynağa.Öncelikle Virtual PC ile 4 tane sanal makina oluşturuyoruz.İlk 2 sanal makinamız Node1 ve Node2,üçüncüsü SCSI Server, ve son olarak da bir Active Directory sanal makinası kuruyoruz.Daha sonra SCSI Server olarak kurduğumuz sanal makinaya Starwind programını kuruyoruz.Ortam şartları artık hazır.Devamını aşağıda verdiğim linkteki pdf i indirerek görsel şekilde anlayarak uygulayabilirsiniz.Kolay gelsin...

Starwind programını indirmek için  --> http://www.starwindsoftware.com/

Kaynak pdf --> www.starwindsoftware.com/images/content/StarWind_MSCluster2008.pdf

String.Empty ve "" karşılaştırması

benim için beklenmedik bir şekilde performans açısından kazanan string.empty!

bugün aşağıdaki örnekteki str1 ve str2 değişkenlerinin durumunu ve bir farkı olup olmadığını inceleyeceğiz.


class StringDeneme
{
static void Main()
{
string str1 = string.Empty;
string str2 = "";
}
}


yukarıdaki kodu console projesinde derleyip oluşan .exe'mizi ildasm ile incelediğimizde şu kodu görüyoruz:


.method private hidebysig static void Main() cil managed
{
.entrypoint
// Code size 14 (0xe)
.maxstack 1
.locals init ([0] string str1, [1] string str2)
IL_0000: nop
IL_0001: ldsfld string [mscorlib]System.String::Empty
IL_0006: stloc.0
IL_0007: ldstr ""
IL_000c: stloc.1
IL_000d: ret
} // end of method Program::Main


str1 değişkenimize string [mscorlib]System.String::Empty değeri atanmış (ldsfld) yöntemiyle.
str2 değişkenimize "" değeri atanmış (ldstr) yöntemiyle.

msdn'nden ldsfld'nin açıklamasına baktığımızda: gelen değeri direkt olarak değişkene atadığını görüyoruz. yani str1 değişkenine direkt olarak string.empty değeri atanmış.

ldstr'nin açıklamasına baktığımızda ise: gelen değer için bir string objesi yaratılıp değişkene atandığını öğreniyoruz. yani str2 değişkenine atanmak üzere bir string objesi yaratılıyor.

.NET Reflector yardımı ile mscorlib içinden [mscorlib]System.String::Empty değerine baktığımızda ise string class'ının constructor'ında Empty değeri olarak "" atandığını görüyoruz.


static String()
{
Empty = "";
WhitespaceChars = new char[] {
'\t', '\n', '\v', '\f', '\r', ' ', '\x0085', '\x00a0', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
' ', ' ', ' ', ' ', '​', '\u2028', '\u2029', ' ', ''
};
}


kodunu görüyoruz. Yani aslında str1 = "" demiş oluyoruz. bana string.empty yöntemi çok daha maliyetli geldi... demiştim fakat performans testlerim sırasında string.empty yönteminin hep daha performanslı olduğunu gördüm. bunun üzerine ldsfld ve ldstr'yi araştırınca ldstr'de string objesinin yaratılmasından ötürü bu farkın oluştuğunu öğrenmiş oldum.

performans testi sonuçları 10.000.000 deneme için şu şekilde, str2 = ""; ifadesini oluşturmak hep daha fazla zaman almış:


/* -------- Deneme 1 -------- */
Name Time (msec)
StringDeneme.str2 4.627,05
StringDeneme.str1 4.282,18
/* -------------------------- */

/* -------- Deneme 2 -------- */
Name Time (msec)
StringDeneme.str2 4.816,66
StringDeneme.str1 3.765,69
/* -------------------------- */


kaynaklar:
OpCodes.Ldsfld Field
OpCodes.Ldstr Field
OpCodes.Stloc Field
OpCodes.Nop Field
OpCodes.Ret Field

22 Aralık 2010 Çarşamba

TC Kimlik No Algoritması

Oluşabilecek tüm kimlik numaralarını hesaplayan algoritmayı aşağıda bulabilirsiniz. Bu sayede tam hatırlayamadığınız bir kimlik numarasını bulabilirsiniz mesela. Ben bu yüzden kullanmıştım bu algoritmayı.


for (int a1 = 1; a1 < 10; a1++)
for (int a2 = 0; a2 < 10; a2++)
for (int a3 = 0; a3 < 10; a3++)
for (int a4 = 0; a4 < 10; a4++)
for (int a5 = 0; a5 < 10; a5++)
for (int a6 = 0; a6 < 10; a6++)
for (int a7 = 0; a7 < 10; a7++)
for (int a8 = 0; a8 < 10; a8++)
for (int a9 = 0; a9 < 10; a9++)
{
int tekBasamaklar = a1 + a3 + a5 + a7 + a9;
int ciftBasamaklar = a2 + a4 + a6 + a8;
int t1 = (tekBasamaklar * 3) + ciftBasamaklar;
int c1= (10 - (t1 % 10)) % 10;

int t2 = c1 + ciftBasamaklar;
int t3 = (t2 * 3) + tekBasamaklar;
int c2 = (10 - (t3 % 10)) % 10;

string tc = String.Format("{0}{1}{2}{3}{4}{5}{6}{7}{8}{9}{10}", a1, a2, a3, a4, a5, a6, a7, a8, a9, c1, c2);
Console.WriteLine(tc);
}

ya da bu algoritmayla biraz daha oynayıp şu şekilde işler yapabilirsiniz:


/// Girilen 9 basamaklı sayının son iki basamağını bulup TC Kimlik No oluşturur
string tc = Console.ReadLine();
int[] digit = new int[9];
for (int i = 0; i < 9; i++)
digit[i] = Convert.ToInt32(tc.Substring(i, 1));

int tekBasamaklar = digit[0] + digit[2] + digit[4] + digit[6] + digit[8];
int ciftBasamaklar = digit[1] + digit[3] + digit[5] + digit[7];
int t1 = (tekBasamaklar * 3) + ciftBasamaklar;
int c1 = (10 - (t1 % 10)) % 10;

int t2 = c1 + ciftBasamaklar;
int t3 = (t2 * 3) + tekBasamaklar;
int c2 = (10 - (t3 % 10)) % 10;

string result = String.Format("{0}{1}{2}{3}{4}{5}{6}{7}{8}{9}{10}", digit[0], digit[1], digit[2], digit[3], digit[4], digit[5], digit[6], digit[7], digit[8], c1, c2);
Console.WriteLine(result);