Çoklu Monitör Kullanımında Ekranı Farklı Monitörde Açma

Çalışmakta olduğum bir projede kullanıcılar ekrandan tıklama yaparak yeni bir pencere açmakta ve açılan penceredeki bilgiler doğrultusunda ana pencerede işlem yapmaktadırlar. Ancak çift monitör ile çalışan kullanıcılar yeni pencerenin ana pencere ile aynı monitörde açılması nedeniyle her defasında yeni pencereyi sürükleyerek diğer monitöre aktarmakta ve bu da zaman kaybına yol açmaktadır. Bu nedenle açılacak olan yeni pencerenin ana pencerenin bulunduğu monitörden farklı diğer moniterde açılması için düzenleme yapma kararı aldık.

Bu noktada ilk akla gelen çözüm sunucu tarafında yeni bir process ile pencere açmak ve SetWindowPos metodu ile açılan pencereyi ilgili ekrana taşımaktır. Temel çalışma mantığı aşağıdaki gibi olacaktır.

ProcessStartInfo startInfo = new ProcessStartInfo("IExplore.exe");
startInfo.Arguments = url;
Process newProcess = System.Diagnostics.Process.Start(startInfo);
IntPtr newProcessPtr = newProcess.MainWindowHandle;
SetWindowPos(newProcessPtr, IntPtr.Zero, x, y, cx, cy, SetWindowPosFlags.ShowWindow);

SetWindowPos metodu pencerenin pozisyonunu x ve y parametreleri ile almaktadır. cx ve cy ise pencere boyutlarını belirlemektedir. Bu noktada ana pencerenin hangi ekranda olduğunun bilinmesi ve yeni açılacak pencerenin de buna göre hangi pozisyonda açılacağının hesaplanması gerekmektedir.

Ekran bilgilerini almak için System.Windows.Forms kütüphanesi içinde Screen sınıfı bulunmaktadır. Bu sınıfın AllScreens adlı özelliği bilgisayara bağlı tüm ekranları yine Screen sınıfından bir dizi ile vermektedir. Screen sınıfının sınır koordinatlarından haraketle ekranları aşağıdaki gibi sıraya dizmek mümkündür.

List<KeyValuePair<int, int>> screenList = new List<KeyValuePair<int, int>>();
for (int i = 0; i < Screen.AllScreens.Length; i++)
      screenList.Add(new KeyValuePair<int, int>(i, Screen.AllScreens[i].Bounds.X));
screenList.Sort((firstPair, nextPair) =>
{
      return firstPair.Value.CompareTo(nextPair.Value);
});

Javascript tarafında ana pencerenin bulunduğu pozisyon bilgisini window.screenLeft ile alıp sunucu tarafına aktarabiliriz. Bu değer üzerinden sıralanmış ekranlar içinde açılacak olan yeni pencerenin ekranını belirlemek mümkün olacaktır.

int targetScreenId = 0;
foreach (KeyValuePair<int, int> screen in screenList)
{
      if (screen.Value > screenLeft)
          targetScreenId = screen.Key;
}

Açılacak yeni pencerenin konumu belirlendikten sonra değerleri SetWindowPos metoduna aktarılabilir. Burada pencere boyutları için ekran boyutlarını geçerek pencerenin tam ekran olarak açılmasınını sağlıyoruz.

SetWindowPos(newProcessPtr, IntPtr.Zero,
Screen.AllScreens[targetScreenId].WorkingArea.Left, 
Screen.AllScreens[targetScreenId].WorkingArea.Top, 
Screen.AllScreens[targetScreenId].Bounds.Size.Width, 
Screen.AllScreens[targetScreenId].Bounds.Size.Height, 
SetWindowPosFlags.ShowWindow);

1
2

Bu hali ile kodumuzu çalıştırdığımızda process üzerinden MainWindowHandle ulaştığımız anda “Process has exited, so the requested information is not available.” şeklinde istisna fırlatıldığını görürüz. Bu durum aşağıdaki sayfada açıklanmış ve çözümü verilmiştir.

http://stackoverflow.com/questions/1825105/process-startiexplore-exe-immediately-fires-the-exited-event-after-launch

Most probably is that you have IE already running as a process, so when you try to launch it again as a new process it looks that there are IE running already, tells it that user initiated a new window (so the initial IE will create a “new” window rather than a new one) and exit. Possible solution: try starting the process with “-nomerge” command line option.

“-nomerge” komutu IE8 öncesi tarayıcılarda kullanılmakta olup IE8 ve sonrası için bu komut yerine “-noframemerging” komutu kullanılmaktadır. Detaylı bilgi için aşağıdaki bağlantıyı inceleyebilirsiniz.

https://msdn.microsoft.com/en-us/library/hh826025(v=vs.85).aspx

ProcessStartInfo startInfo = new ProcessStartInfo("IExplore.exe");
startInfo.Arguments = "-noframemerging " + url;
Process newProcess = System.Diagnostics.Process.Start(startInfo);

Bu hali ile kodumuzu çalıştırdığımızda istediğimizin gerçekleşmediğini görürüz. Debug ettiğimizde ise newProcessPtr değerinin 0 olduğu ortaya çıkar. Bu durum aşağıdaki sayfada açıklanmış ve çözümü verilmiştir.

https://social.msdn.microsoft.com/Forums/vstudio/en-US/021c76c6-1a66-4b96-8ce7-89c2a12f4bcb/procstart-procwaitforinputidle-setwindowpos-does-not-work?forum=csharpgeneral

The reason for SetWindowPos method execution failed is that the Process. MainWindowHandle is not acquired in time, it is still 0 when SetWindowPos was executed.As BinaryCoder suggested, all we need to do is add a loop to check the handle status, we all in the loop until the handle was obtained.

int count = 0;
while (newProcess.MainWindowHandle == IntPtr.Zero && count < 2000)
{
     Thread.Sleep(20);
     count += 20;
}

IntPtr newProcessPtr = newProcess.MainWindowHandle;

Yukarıdaki durumu araştırırken aşağıdaki gibi bir bilgi ile karşılaştım. Bu nedenle döngü içine newProcess.Refresh(); eklemenin doğru olacağını düşünüyorum.

The main window is the window opened by the process that currently has the focus (the TopLevel form). You must use the Refresh method to refresh the Process object to get the current main window handle if it has changed.

Sonuç olarak birden fazla monitör kullanan kullanıcılarda açılacak olan yeni pencerenin ana pencerenin bulunduğu monitörden farklı bir moniterde açılmasını sağlayan kodumuz aşağıdaki gibidir.

if (Screen.AllScreens.Length > 1)
{
        ProcessStartInfo startInfo = new ProcessStartInfo("IExplore.exe");
        startInfo.WindowStyle = ProcessWindowStyle.Maximized;
        startInfo.Arguments = "-noframemerging " + url;

        Process newProcess = System.Diagnostics.Process.Start(startInfo);

        if (newProcess.Id >= 0)
        {
               int count = 0;
               while (newProcess.MainWindowHandle == IntPtr.Zero && count < 2000)
               {
                      Thread.Sleep(20);
                      newProcess.Refresh();
                      count += 20;
               }
               IntPtr newProcessPtr = newProcess.MainWindowHandle;

               List<KeyValuePair<int, int>> screenList = new List<KeyValuePair<int, int>>();

               for (int i = 0; i < Screen.AllScreens.Length; i++)
                    screenList.Add(new KeyValuePair<int, int>(i, Screen.AllScreens[i].Bounds.X));

               screenList.Sort((firstPair, nextPair) =>
               {
                    return firstPair.Value.CompareTo(nextPair.Value);
               });

               int targetScreenId = 0;
               foreach (KeyValuePair<int, int> screen in screenList)
               {
                    if (screen.Value > screenLeft)
                           targetScreenId = screen.Key;
               }

               SetWindowPos(newProcessPtr, IntPtr.Zero, Screen.AllScreens[targetScreenId].WorkingArea.Left, Screen.AllScreens[targetScreenId].WorkingArea.Top,             Screen.AllScreens[targetScreenId].Bounds.Size.Width, Screen.AllScreens[targetScreenId].Bounds.Size.Height, Win32.SetWindowPosFlags.ShowWindow);

       }
}
Reklamlar

Yazılım Kalitesi

Bilişim sektöründeki yazılım maliyetlerinin büyümesiyle birlikte, yazılımda kalite kavramı günümüzde üzerinde en çok çalışılan konulardan biri haline gelmiştir. Yazılım dünyasında kalite, kavram olarak herkesin hissedebildiği ancak neticede tam olarak tanımlayamadığı soyut ve sübjektif bir olgu olarak karşımıza çıkmaktadır. Bu disiplin içerisinde kalitenin tam olarak tanımlanabilmesi için gelişmiş ölçme araçlarına ve sağlıklı karşılaştırmalar için tanımlı referans noktalarına ihtiyaç vardır. Ancak yazılım sektöründe bu iki olgu henüz çok gelişmemiş durumdadır.

Yazılım kalitesi temelde müşteri gözünden ve yazılım üreticisi gözünden olmak üzere iki farklı bakış açısıyla ele alınabilir. Müşteriler genel olarak satın aldıkları yazılımların kolay kullanılabilir, hatasız, tüm istekleri karşılayan ve yeterli performansa sahip olmasını isterler. Buna karşılık yazılım üreticileri ise geliştirme ve bakım maliyetlerinin düşük ve üretilen yazılım parçalarının bir sonraki projelerde de kullanılabilir olmasını isterler.
ISO 9126, kalite kavramını ürün temelli olarak müşteri gözünden ele alan ve sınıflandıran uluslar arası bir standarttır. ISO 9126’ya göre kalite sınıfları şunlardır:

  • İşlevsellik: Yazılımın ihtiyaçları karşılama becerisi olarak tanımlanmaktadır. Uygunluk, doğruluk, birlikte çalışılabilirlik ve güvenlik konuları bu sınıf altında incelenmektedir.
  • Güvenilirlik: Yazılımın düzgün çalışma halini muhafaza edebilme becerisi olarak tanımlanmaktadır. Olgunluk, hata toleransı ve geri kurtarma konuları bu sınıf altında incelenmektedir.
  • Kullanılabilirlik: Yazılımın kullanım kolaylığı sağlayan yetenekleri olarak tanımlanmaktadır. Öğrenebilme, anlaşılabilirlik, işletilebilirlik ve kullanıcı etkileşimi konuları bu sınıf altında incelenmektedir.
  • Verimlilik: Yazılımın ihtiyaç duyulan ölçüde yeterli performansla çalışabilme becerisi olarak tanımlanmaktadır. Zaman ve kaynak kullanımı konuları bu sınıf altında incelenmektedir.
  • Bakılabilirlik: Yazılımın değişiklik veya düzeltme isteklerine adaptasyon yeteneği olarak tanımlanmaktadır. Değiştirilebilirlik, test edilebilirlik, analiz edilebilirlik ve bağışıklık konuları bu sınıf altında incelenmektedir.
  • Taşınabilirlik: Yazılımın çalıştığı ortam değişikliklerine uyum sağlayabilme yeteneği olarak tanımlanmaktadır. Adaptasyon yeteneği, yüklenebilirlik özellikleri, ortam değiştirme imkânı ve diğer yazılımlarla uyum konuları bu sınıf altında incelenmektedir.

Üretilen bir yazılımın müşterilerine bakan dış özellikleri iç özelliklerinin bir yansımasıdır. Nesneye dayalı yazılımlarda bağımlılık, uyumluluk ve karmaşıklık yazılımın en önemli iç özellikleridir. En genel anlamda bağımlılık, yazılım parçaları arasında karşılıklı bağımlılığın derecesini, uyumluluk yazılım parçalarının kendi yaptıkları işlerdeki tutarlılığın derecesini, karmaşıklık ise yazılımın içyapısının kavranmasındaki zorluğun derecesini belirtir. Kaliteli yazılımların uyumluluğunun yüksek, karmaşıklığının ve bağımlılığının düşük olduğu yaygın olarak kabul görmüş bir olgudur.

Matematiksel olarak, nesneye dayalı bir yazılımda, bir nesne X = (x, p(x)) seklinde gösterilebilir. Burada x nesnenin tanımlayıcısı, p(x), nesnenin sonlu sayıdaki özelliklerinin belirtir. Nesnenin nitelik değişkenleri ve metotları nesnenin özelliklerini oluştururlar. Mx metotlar kümesi, Ix nitelik değişkenleri kümesi olmak üzere nesnenin özellikleri p(x) = {Mx} U {Ix} şeklinde gösterilebilir.

  • Bağımlılık (Coupling) 

    Ontolojik terminolojide, bağımlılık iki nesneden en az birinin diğerine etki etmesi olarak tanımlanır. A nesnesinin B nesnesine etki etmesi, B’nin kronolojik durumlarının sırasının A tarafından değiştirilmesidir. Bu tanıma göre Ma’nın Mb ya da Ib üzerinde herhangi bir eylemi, aynı şekilde Mb’nin Ma ya da Ia üzerinde eylemi, bu iki nesne arasında bağımlılığı oluşturur.Aynı sınıfın nesneleri aynı özellikleri taşıdıklarından, A sınıfının B sınıfına bağımlılığı aşağıdaki durumlarda oluşur.

    • A sınıfının içinde B sınıfı cinsinden bir üye (referans, işaretçi ya da nesne) vardır.
    • A sınıfının nesneleri B sınıfının nesnelerinin metotlarını çağırıyordur.
    • A sınıfının bir metodu parametre olarak B sınıfı tipinden veri (referans, işaretçi ya da nesne) alıyordur ya da geri döndürüyordur.
    • A sınıfının bir metodu B sınıfı tipinden bir yerel değişkene sahiptir.
    • A sınıfı, B sınıfının bir alt sınıfıdır.

    Bir sınıfın bağımlılığı; işleri için başka sınıfları ne kadar kullandığı, başka sınıflar hakkında ne kadar bilgi içerdiği ile ilgilidir. Yüksek bağımlılık aşağıdaki sorunlara yol açmaktadır.

    • Bir sınıftaki değişim ana bağımlı diğer sınıfları da etkiler. (maintability)
    • Bağımlı sınıfları birbirinden ayrı olarak anlamak zordur. (understandibility)
    • Bağımlı sınıfları tekrar kullanmak zordur. (reusability)
  • Uyumluluk (Cohesion) 

    Bunge benzerliği σ(), iki varlık arasındaki özellik kümesinin kesişimi olarak adlandırılmaktadır. Benzerliğin bu genel tanımından yola çıkarak metotlar arasındaki benzerliğin derecesi, bu iki metot tarafından kullanılan nitelik değişkenleri kümesinin kesişimi olarak tanımlanmaktadır. Elbette metodun kullandığı nitelik değişkenleri metodun özellikleri değildir ama nesnenin metotları, kullandığı nitelik değişkenlerine oldukça bağlıdır.σ(M1,M2), M1 ve M2 metotlarının benzerliği, {Ii} = Mi metodu tarafından kullanılan nitelik değişkenleri olmak üzere σ(M1,M2) = {I1} n {I2}’dir.Metotların benzerlik derecesi, hem geleneksel yazılım mühendisliğindeki uyumluluk kavramı ile hem de kapsülleme ile ilişkilidir. Metotların benzerlik derecesi, nesne sınıfının uyumluluğunun başlıca göstergesi olarak kabul görülebilir. Uyumluluk bir sınıftaki metot ve niteliklerin birbirleriyle ilgili olmasının ölçüsüdür. Bir sınıftaki metot parametrelerindeki ve nitelik tiplerindeki güçlü örtüşme iyi uyumluluğun göstergesidir. Eğer bir sınıf aynı nitelik değişkenleri kümesi üzerinde farklı işlemler yapan farklı metotlara sahipse, uyumlu bir sınıftır. Eğer bir sınıf birbiri ile ilgili olmayan işler yapıyorsa, birbirleriyle ilgili olmayan nitelik değişkenleri barındırıyorsa veya çok fazla iş yapıyorsa sınıfın uyumluluğu düşüktür.

  • Karmaşıklık (Complexity) 

    Karmaşıklık, sınıfların iç ve dış yapısını, sınıflar arası ilişkileri kavramadaki zorluğun derecesidir. “Bir nesnenin karmaşıklığı bileşiminin çokluğudur. Buna göre karmaşık bir nesne çok özelliğe sahip olur. Tanımdan hareketle (x, p(x)) nesnesinin karmaşıklığı özellik kümesinin kardinalitesi yani |p(x)| olur.

Düşük Kaliteli Kod Göstergeleri

Yazılım yaşam döngüsü boyunca sürekli değişim halindedir. Bu değişiklikler bazen dağınık kodları toparlama bazen de uygulamanın yapısını değiştirme şeklinde olabilir. Yazılım geliştiriciler, kod üzerinde değişiklik yaparken kalitesizlik göstergelerini fark ederek gerekli düzeltmeleri yapmalıdırlar. Bu göstergelerin büyük bir çoğunluğu metrik değerlerini olumsuz yönde değiştirirken, bazıları metriklerle analiz sırasında gözden kaçabilir. Kalitesiz kod göstergeleri kavramı ilk olarak, Martin Fowler tarafından var olan kodların iyileştirilmesi için ortaya koyulmuştur. Aşağıda düşük kaliteli kod göstergelerinden bazıları verilmiştir.

  • Tekrar Eden Kod Parçaları: Aynı kod parçasının birden çok yerde gözükmesidir. Bu kod parçalarının metot haline getirilmesi tavsiye edilir. Tanımlanan metriklerle bu tasarım kusurunu fark edecek bir yöntem bulunmamaktadır.
  • Uzun Metot: Nesneye dayalı programlarda metotların kısa olması yeğlenir. Ağırlıklı metot sayısı metriklerinde, ağırlık ölçüsü olarak metodun kod uzunluğu alınırsa, bu kusur fark edilebilir.
  • Büyük Sınıf (God Class): Çok fazla iş yapan, çok sayıda üye nitelik değişkeni veya kod tekrarı bulunduran sınıflar büyük sınıflardır. Bu sınıfların yönetimi zordur. Uyumluluk metrik değeri düşük, bağımlılık metrik değeri yüksek olan sınıfların büyük sınıf olma ihtimali yüksektir.
  • Uzun Parametre Listesi: Uzun parametre listelerinin anlaşılması, kullanımı zordur ve ileride yeni verilere erişilmek isteneceğinden sürekli değişiklik gerektirir. Uzun parametre listesi olan sınıfların metotlar arası uyumluluk metrikleri genellikle düşük çıkar.
  • Farklı Değişiklikler (Divergent Change): Farklı tipte değişiklikler için kodda tek bir sınıf üzerinde değişiklik yapılmasıdır. Bu tasarım kusurunu tanımlanan metriklerle tespit etmek oldukça zordur. Ancak bu özelliğin bulunduğu sınıfın uyumluluk metriğinin düşük çıkması beklenir.
  • Parçacık Tesiri (Shotgun Surgery): Bir değişiklik yapılması gerektiğinde kodda birçok sınıfta küçük değişiklik yapılmasının gerekmesidir. Böyle bir durumda önemli bir değişikliğin atlanma ihtimali yüksektir. Parçacık tesiri tespit edilen sınıflarda karmaşıklık ve bağımlılık metriğinin yüksek olması beklenir.
  • Veri Sınıfı: Sadece veriler ve bu verilerin değerlerini okumak ve yazmak için gerekli metotları barındıran ve başka hiçbir iş yapmayan sınıflardır. Tanımlanan metriklerle bu tür kusurları bulmak çok kolay gözükmemektedir. Ancak sınıfın açık ve gizli metotlarının oranı bu konuda yardımcı olabilir.
  • Reddedilen Miras: Türetildiği sınıfın sadece küçük bir parçasını kullanan sınıflar bu durumu oluştururlar. Bu kalıtım hiyerarşisinin yanlış olduğunun bir göstergesidir.

Tasarım Kalıpları

Tasarım kalıpları ilk olarak mimar Christopher Alexander tarafından kaliteli mimari yapılardaki ortak özelliklerin sorgulanması ile ortaya çıkmıştır. C. Alexander yaptığı araştırmalar sonucunda beğenilen yapılarda benzer problemlerin çözümünde benzer çözüm yollarına başvurulduğunu belirlemiş ve bu benzerliklere tasarım kalıpları adını vermiştir.

Yazılım dünyasında bu konudaki ilk önemli çalışma kendilerine dörtlü çete (Gang of Four) adı takılan dört yazar tarafından ortaya konmuştur. GoF tasarım kalıpları olarak adlandırılan çalışma üç gruptan oluşmaktadır.

  • Yaratımsal Kalıplar 

    Bu gruptaki kalıplar nesne yaratma sorumluluğunun sınıflar arasında etkin paylaştırılması ile ilgilidir. Tekil Nesne (Singleton), Soyut Fabrika (Abstract Factory), İnşacı (Builder) kalıplarının yer aldığı bu grup, nesne yaratmanın getireceği ek karmaşıklıkları ve bağımlılıkları en aza indirirken, sınıfların uyumluluğunu yüksek tutmayı amaçlamaktadırlar.

  • Yapısal Kalıplar 

    Bu gruptaki kalıplar, sınıf ve nesnelerin kompozisyonu ile ilgilidir. Genel olarak ara yüzler oluşturmak için kalıtımdan faydalanırlar ve yeni işlevler kazandırmak için nesnelerin yapılarını oluşturacak uygun yöntemler önerirler. Adaptör (Adapter), Köprü (Bridge) ve Ön Yüz (Facade) bu gruptaki bazı kalıplardır.

  • Davranışsal Kalıplar 

    Bu kalıplar özellikle nesneler arasındaki iletişimle ilgilidir. Bu kalıplar aracılığı ile yazılım, ihtiyaçlara göre kolayca genişletilebilir, hataların yerleri daha çabuk tespit edilebilir. Bu gruptan sıkça başvurulan kalıplar ise Gözlemci (Observer) ve Strateji (Strategy)’dir.

Aşağıda bazı sık kullanılan tasarım kalıpları açıklanmıştır.

  • Adaptör (Adapter) 

    İstenen işi yapan fakat farklı ara yüzleri olan benzer birimler için tek bir kararlı ara yüz oluşturulmak isteniyorsa adaptör kalıbı kullanılır.
    adaptör

  • Fabrika (Factory) 

    Nesnelerin yaratılmasında karmaşık kararlar vermek gerekiyorsa ve uyumluluğu arttırmak için nesne yaratma işleminin diğer işlemlerden ayrı ayrılması isteniyorsa fabrika kalıbı kullanılır.
    fabrika
    Fabrika sınıfı o andaki kıstaslara göre aynı üst sınıftan (interface) türeyen sınıflar arasından hangisini yaratacağına karar vererek yarattığı sınıfın adresini üst sınıf değişkeni ile geri döndürür.

  • Tekil Nesne (Singleton) 

    Bir sınıftan sadece tek bir nesne yaratılması ve bu nesnenin diğer nesnelere global tek bir erişim noktası sağlanması isteniyorsa tekil nesne kalıbı kullanılır.tekilnesneSınıf içinde kendi tipindeki nesnelere işaret edebilen statik bir değişken ve sınıf nesnelerini yaratan yine statik bir metot eklenir. Sınıf dışında bu sınıftan bir nesne üretilmemesi için kurucu metot özel (private) yapılır.

  • Stateji (Strategy) 

    Bir sınıfın belli bir konudaki davranışının o sınıftan yaratılan bir nesnenin yaşamı süresince defalarca değişmesi istenebilir. Birbiriyle ilgili olan fakat farklılık gösteren bu davranışların gerçeklenmesi için strateji kalıbı kullanılır.strateji
    Bu tasarım kalıbında her davranış aynı ara yüzden türeyen ayrı birer sınıf olarak gerçeklenir.

  • Bileşik Nesne (Composite) 

    Bir nesnenin belli bir iş için tek bir nesne (atomik nesne) ile ilişkilendirilebildiği gibi birden fazla nesne grubu (bileşik nesne) ile ilişkilendirilmesi de isteniyor, esnekliği sağlamak için ilgili nesnenin o iş tek bir nesne ile mi yoksa bir nesne grubuyla mı ilişkili içinde olduğundan habersiz olması isteniyorsa bileşik nesne kalıbı kullanılır.BileşikNesneAtomik ve bileşik nesneler, aynı ara yüzden türetilerek bileşik nesne içerisine atomik nesneleri içeren bir liste yerleştirilir.

  • Ön Yüz (Facade) 

    İleride değişme olasılığı bulunan ve bazı alt parçaları kullanılmak istenen, değişik ara yüzlere ve yapılara sahip hizmetleri içeren bir alt sistem ile bağlantı kurulmak isteniyorsa ön yüz kalıbı kullanılır.ÖnyüzAlt sistem ile bağlantıyı sağlayan bir ön yüz nesnesi tanımlanarak, bu nesne içine kullanıcı sistemin gerek duyduğu işleri yapan metotlar yerleştirilir. Kullanıcı sistem bu metotları çağırdığında metotların içinde alt sistemin gerekli yerlerine erişilir.

  • Gözlemci (Observer) 

    Değişik tipteki abone nesnelerinin yayıncı nesnelerindeki durum değişikliklerini sezmesi ve bu değişimlere kendilerine göre tepki göstermesi isteniyorsa gözlemci kalıbı kullanılır.Gözlemci

    Abone nesneleri ortak bir ara yüzden türetilir. Yayıncı nesne isteyen aboneleri kendi listesine kayıt eder. Yayıncı nesne kendi durumunda bir değişiklik olduğunda listesindeki abonelere durumu iletir.

  • Köprü (Bridge) 

    Soyutlama ve gerçeklemenin bir arada ilişki içinde kullanılması ve olası değişikliklerden sistemin en az etkilenmesi isteniyorsa köprü kalıbı kullanılır.Köprü

    Farklı türlerdeki soyutlama ve gerçekleme sınıfları kendi içlerinde ortak bir ara yüzden türetilerek soyutlama sınıfının gerçekleme sınıfına işaret eden bir işaretçiye sahip olması sağlanır. Çalışma anında her soyutlama nesnesi kendi işlemini gerçekleştirmek için sahip olduğu işaretçinin gösterdiği gerçekleme nesnesi ile mesajlaşır.

  • Dekoratör (Decorator) 

    Bir nesnenin davranışı bir dizi işlemden oluşuyor ve işlemlerin sayısı ve sırası çeşitli koşullara göre değişiyorsa dekoratör kalıbı kullanılır.
    DekoratörTüm alt işlemler ortak bir ara yüzden türeyen ayrı bir dekoratör sınıfı olarak tasarlanır. Programın çalışması sırasında, dekoratör sınıflardan oluşturulan nesneler istenilen sırada bir listeye eklenir.

İlgilerin Ayrıştırılması (Separation of Concerns)

İlgilerin ayrıştırılması bir yazılımın aynı alana yönelik işlerini gerçekleştiren parçalarının ortak bir çatı altında toplanması şeklinde tanımlanır.

  • Modül Düzeyi İlgiler
    Bir modülün temel olarak yapması gereken işler.
  • Sistem Düzeyi İlgiler
    Loglama, hata kontrolü, yetki denetimi gibi bütün sistem tarafından ihtiyaç duyulan görevler.

Sistem düzeyi ilgilerin bütün modüllerden çağırılması (modül düzeyi ilgileri dik kesmesi) bağımlılığı (coupling) arttırarak kod karıştırmaya (code tangling) yol açar. Aynı zamanda bir yöntem içinde sistem düzeyi ilgilere olan bağlantı arttıkça uyumluluk (cohesion) düşer ve bu da kod dağıtmaya (code scattering) neden olur.

Cepheye Yönelik Programlama (AOP – Aspect Oriented Programming)

Yazılımı ilgi düzeyinde ele alarak nesne yönelimli programlama metodolojisinin çözüm üretmekte zorlandığı dik kesen ilgiler (cross-cutting concerns) konusuna çözüm getiren bir yaklaşımdır. Nesne yönelimli programlamanın yerine geçmeyip onu geliştirilecek bir adım olarak ortaya çıkmıştır.

  • Sınıf (Class)
    OOP teknikleri ile gerçeklenmiş ve sistemin ana işlevini (modül düzeyi ilgiler) tanımlayan yapılardır.
  • Cephe (Aspect)
    AOP teknikleri ile gerçeklenmiş ve sistemdeki dik kesen ilgilerin (sistem düzeyi ilgiler) gerçeklendiği yapılardır.

Ayrı olarak gerçeklenmiş olan sınıf ve cephe bileşenlenleri örme (weaving) işlemi ile birleştirilerek bütünsellik sağlanır.

weaving

Cepheye Yönelik Programlama Elemanları

  • Birleşme noktası (Join point) 
    Örme işleminin sınıf üzerinde belirli hangi noktalarda yapılabileceğini belirten işaretşilerdir.
  • Kesim noktası (Pointcut)
    Birleşme noktalarını kullanarak örme şleminin gerçekleşme koşulunu tanımlayan yapılardır.
  • Tavsiye (Advice)
    Sınıf üzerinde tanımlanan birleşme noktalarında, örme işlemine katılarak yapılması istenen işlerlerdir.

aop

Chidamber&Kemerer Metrik Kümesi

Sınıfın Ağırlıklı Metot Sayısı (Weighted Methods per Class – WMC)

Bir sınıfın tüm metotlarının karmaşıklığının toplamıdır. Tüm metotların karmaşıklığı 1 kabul edilirse, sınıfın metot sayısı olur. Sınıfın metotlarının sayısı ve metotlarının karmaşıklığı, sınıfın geliştirilmesine ve bakımına ne kadar zaman harcanacağı hakkında fikir verebilir. Metot sayısı çok olan taban sınıflar, çocuk düğümlerde daha çok etki bırakırlar; çünkü tanımlanan tüm metotlar türetilen sınıflarda da yer alacaktır. Metot sayısı çok olan sınıfların uygulamaya özgü olma ihtimali yüksektir. Bu nedenle tekrar kullanılabilirliği düşürürler.

Kalıtım Ağacının Derinliği (Depth of Inheritance Tree – DIT)

Sınıfın kalıtım ağacının köküne olan uzaklığıdır. Hiçbir sınıftan türetilmemiş olan sınıflar için bu değer 0’dır. Kalıtım hiyerarşisinde daha derinde olan sınıflar, daha çok metot türettiklerinden davranışlarını tahmin etmek zordur. Derin kalıtım ağaçları daha çok tasarım karmaşıklığı oluşturur.

Alt Sınıf Sayısı (Number of Children – NOC)

Sınıftan doğrudan türetilmiş alt sınıfların sayısıdır. Eğer bir sınıf çok fazla sayıda alt sınıfa sahipse, bu durum kalıtımın yanlış kullanıldığının bir göstergesi olabilir. Bir sınıfın alt sınıf sayısı, sınıfın tasarımdaki potansiyel etkisi hakkında fikir verir. Çok alt sınıfı olan sınıfların metotları daha çok test etmeyi gerektireceğinden bu metrik, sınıfı test etmek için harcanacak maliyet hakkında bilgi verir.

Nesne Sınıfları Arasındaki Bağımlılık (Coupling Between Object Classes – CBO)

Sınıfın bağımlı olduğu sınıf sayısıdır. Bu metrikte, bir sınıf içinde nitelik ya da metotlar diğer bir sınıfta kullanılıyorsa, iki sınıf arasında bağımlılık olduğu kabul edilmiştir. Sınıflar arasındaki aşırı bağımlılık modüler tasarıma zarar verir ve tekrar kullanılabilirliği azaltır. Bir sınıf ne kadar bağımsızsa başka uygulamalarda o kadar kolaylıkla yeniden kullanılabilir. Bağımlılıktaki artış, değişime duyarlılığı arttıracağından, yazılımın bakımını zorlaştırır. Bağımlılık aynı zamanda tasarımın farklı parçalarının ne kadar karmaşık test edileceği hakkında fikir verir. Bağımlılık fazla ise testlerin daha özenli yapılması gerektiğinden test maliyetleri artacaktır.

Sınıfın Tetiklediği Metot Sayısı (Response For a Class – RFC)

Verilen sınıftan bir nesnenin metotları çağırıldığında, bu nesnenin tetikleyebileceği tüm metotların sayısıdır. Bu metrik sınıfın test maliyeti hakkında da fikir verir. Bir mesajın çok sayıda metodun çağrılmasını tetiklemesi, sınıfın testinin ve hata ayıklamasının zorlaşması demektir. Bir sınıftan fazla sayıda metodun çağırılması, sınıfın karmaşıklığının yüksek olduğunun işaretçisidir.

Metotların Uyumluluğu (Lack of Cohesion in Methods – LCOM)

Bu metriğin birden çok tanımı olmakla birlikte ilk kez kullanılanı şu şekildedir: C1 sınıfının M1, M2, …, Mn metotları olduğunu ve {li} kümesinin de Mi metodunda kullanılan nitelik değişkenleri kümesi olduğunu kabul edelim. Bu durumda LCOM bu n kümenin kesişiminden oluşan ayrık kümelerin sayısıdır. Daha sonra bu tanım yenilenerek şu şekle getirilmiştir: P hiçbir ortak nitelik değişkeni paylaşmayan metot çiftlerinin kümesi, Q en az bir ortak nitelik değişkeni paylaşan metot çiftlerinin kümesi olsun. Bu durumda LCOM, |P| > |Q| ise |P|-|Q|, aksi halde 0 olur. Bunlarla birlikte literatürde farklı tanımlar da mevcuttur. Sınıfın uyumluluğunun düşük olması, sınıfın iki veya daha fazla alt parçaya bölünmesi gerektiğini gösterir. Düşük uyumluluk karmaşıklığı arttırır, bu nedenle geliştirme aşamasında hata yapma ihtimali yükselir. Ayrıca metotlar arasındaki ilişkisizliklerin ölçüsü sınıfların tasarımındaki kusurların belirlenmesinde de yardımcı olur.

Brito e Abreu MOOD Metrik Kümesi

Metot Gizleme Faktörü (Method Hiding Factor – MHF)

Sistemde tanımlı tüm sınıflardaki görünür (çağrılabilir) metotların, tüm metotlara oranıdır. Bu metrikle sınıf tanımının görünürlüğü ölçülür. Burada kalıtım ile gelen metotlar hesaba katılmamaktadır.

Nitelik Gizleme Faktörü (Attribute Hiding Factor – AHF)

Sistemde tanımlı tüm sınıflardaki görünür (erişilebilir) niteliklerin, tüm niteliklere oranıdır. Bu metrikle sınıf tanımının görünürlüğü ölçülür Burada kalıtım ile gelen metotlar hesaba katılmamaktadır.

Metot Türetim Faktörü (Method Inheritance Factor – MIF)

Sistemde tanımlı tüm sınıflardaki kalıtım ile gelen metot sayısının, tüm metotların (kalıtımla gelenler dâhil) sayısına oranıdır.

Nitelik Türetim Faktörü (Attribute Inheritance Factor – AI)

Sistemde tanımlı tüm sınıflardaki kalıtım ile gelen niteliklerin, tüm niteliklere (kalıtımla gelenler dâhil) oranıdır.

Çok Şekillilik Faktörü (Polymorphism Factor – PF)

Bir C sınıfı için sistemdeki farklı çok şekilli durumların, maksimum olası çok şekilli durumlara oranıdır. Bilindiği gibi türetilen nitelikler ve metotlar alt sınıflarda yeniden tanımlanarak, ana sınıftaki metotları örtebilir (override).

Bağımlılık Faktörü (Coupling Factor – CF)

Sistemde sınıflar arasında var olan bağımlılık sayısının, oluşabilecek maksimum bağımlılık sayısına oranıdır. Burada kalıtımla oluşan bağımlılıklar hesaba katılmamaktadır.

Bansiya ve Davis QMOOD Metrik Kümesi

QMOOD metrikleri, Bansiya ve Davis tarafından yazılımın toplam kalite endeksi hesaplanması için 4 seviyeden oluşan hiyerarşik bir model içinde tanımlanmıştır. En alt seviyede sınıf, metot gibi nesneye dayalı yazılım bileşenleri vardır. 3. seviyede QMOOD metrikleri vardır. QMOOD metriklerinden, karmaşıklık, uyumluluk gibi bir üst seviyedeki yazılım özellikleri hesaplanır. Bu yazılım özelliklerinden de anlaşılabilirlik, esneklik, tekrar kullanılabilirlik gibi en üst seviyedeki kalite nitelikleri hesaplanır. Son olarak kalite niteliklerinden toplam kalite endeksi hesaplanır. QMOOD çalışmasında tanımlanan seviyeler ve bağlar aşağıda gösterilmiştir.

qmood

Ortalama Ata Sayısı (Avarage Number of Ancestors – ANA)

Tüm sınıfların DIT (Kalıtım Ağacının Derinliği – Depth of Inheritance Tree) değerlerinin ortalamasıdır. Metrik değeri yazılımda soyutlamanın kullanımını gösterir.

Metotlar Arası Uyumluluk (Cohesion Among Methods – CAM)

Metotların imzaları arasındaki, benzerliğin ölçüsüdür. Tam tanımı Bansiya’ nın metrik kümesi çalışmasında yer almamaktadır. Literatürde metotların imzalarına bakarak uyumluluk ölçen farklı metrik tanımları bulunmaktadır. Bunlar temelde metotların parametre kullanım matrisi üzerinde çalışırlar ve imzalardaki uyumluluğu tam uyumlu olmaya yakınlıkla kıyaslayarak ölçerler. Metotlar ve tüm parametreler numaralandırılır, i. metodun imzasında, j. parametre kullanılıyorsa, matriste Mij 1 aksi halde 0 olur. CAMC parametre matrisindeki 1 sayısına bakarken, NHD matris satırları arasındaki Hamming uzaklıklarına bakar. SNHD ise NHD metriğinin olası en küçük ve büyük değerine göre ölçeklenmiş halidir.

Sınıf Arayüz Boyutu (Class Interface Size – CIS)

Sınıfın açık (public) metotlarının sayısıdır ve yazılımın mesajlaşma özelliği hakkında fikir verir.

Veri Erişim Metriği (Data Access Metric – DAM)

Sınıfın özel (private) ve korumalı (protected) niteliklerinin tüm niteliklere oranıdır. Bu metrik yazılımın kapsülleme özelliğini gösterir.

Doğrudan Sınıf Bağımlılığı (Direct Class Coupling – DCC)

Bir sınıfı parametre olarak kabul eden sınıfların sayısı ile bu sınıfı nitelik değişkeni olarak barındıran sınıfların sayısının toplamıdır. Sınıfın bağımlılığı bu metriğe bakarak anlaşılabilir.

Kümeleme Ölçüsü (Measure Of Aggregation – MOA)

Kullanıcı tarafından tanımlanmış sınıf bildirimlerinin, tanımlı temel sistem veri tiplerine (int, char, double vs… ) oranıdır.

İşlevsel Soyutlama Ölçüsü (Measure of Functional Abstraction – MFA)

Sistemde tanımlı tüm sınıflardaki türetilmiş metot sayısının, tüm metot sayısına (türetilmiş metotlar dâhil) oranıdır. Yazılım kalıtım özelliği bu metrikle belirlenir.

Metot Sayısı (Number of Methods – NOM)

Sınıfta tanımlı metot sayısı tüm metotlar bir birim kabul edilirse WMC metriği ile aynı değeri taşır. Sınıfın metot sayısı sınıfın karmaşıklığının bir göstergesidir.

Yardımcı Araçlar

FindBugs (http://findbugs.sourceforge.net/)

Maryland üniversitesi tarafından geliştirilmiş açık kaynaklı bir statik kod analiz aracıdır. Yazılımın mevcut Java kodu üzerinde çeşitli analizler yaparak, yaygın yazılım hatalarını ve tasarım kusurlarını otomatik olarak kısa sürede bulabilmektedir. Findbugs; java, netbeans, jboss gibi günümüzde popüler olan birçok programın geliştirme aşamalarında da etkin şekilde kullanılmaktadır.

Metrics (http://metrics.sourceforge.net/)

Eclipse projesine bir eklenti olarak geliştirilen açık kaynak kodlu bir başka programdır. Eclipse geliştirme ortamındaki Java projelerine, tümleşik biçimde çalışabilen program, yaygın kullanılan birçok yazılım metriğini otomatik olarak ölçerek geliştiriciye raporlamaktadır. Statik fonksiyon sayısı, türeme derinliği, bağımlılık, fonksiyon karmaşıklığı, soyutlama adedi gibi metrikler bunlardan yalnızca birkaçıdır. Metrics programı aynı zaman yazılımdaki bağımlılıkları grafiksel olarak gösterme yeteneğine de sahiptir. Bu sayede geliştiricilerinin yazılımdaki bağımlıkları görsel olarak daha iyi analiz edebilmeleri mümkün olmaktadır. Aşağıda Metrics programı ile üretilmiş örnek bir çıktı verilmiştir.

Metrics

PMD (http://pmd.sourceforge.net/)

PMD bir statik kod analiz aracıdır. Java kodları üzerinde çalışan bu program mevcut kod üzerinde otomatik analizler yaparak olası kusurları; kullanılmayan, tekrarlanmış ve gereksiz kod parçalarını hızlıca bulmaktadır.

Coverlipse (http://coverlipse.sourceforge.net/)

Gerçekleme yani yazılım kodu ile gereksinimler ve test senaryolarının arasındaki örtüşme ilişkilerini inceleyen açık kaynak kodlu bir Eclipse eklentisidir. Program yazılım geliştirmenin bu üç temel aşaması arasındaki örtüşme ilişkilerini analiz ederek aradaki boşlukları ortaya çıkartmaktadır. Dolayısıyla unutulmuş bir gereksinime veya test edilmemiş bir yazılım parçasına yer vermemeye yardımcı olmaktadır.

CheckStyle (http://checkstyle.sourceforge.net/)

Yazılımın yapısından çok formatı ile ilgilenen bir açık kaynak kodlu yazılım aracıdır. Mevcut Java kodlarının üzerinde format analizi yaparak geliştiricilerin kod yazım standartlarına uyumlu çalışmalarına yardımcı olmaktadır. Kurumun kendi yazım standartlarını da oluşturabileceği bu yazılımda, aynı zamanda genel kabul görmüş kimi uluslararası yazım standartları da mevcuttur.

SDMetrics (http://www.sdmetrics.com/)

Kod üzerinde değil de UML tasarım dokümanları üzerinde çeşitli görsel ve sayısal analizler yapabilen ticari bir programdır. Program, tasarım aşamasından yani geliştirme aşaması başlamadan yazılımın tasarımını analiz ederek bağımlılık ve karmaşıklığa dair birçok uygunsuzluğu ortaya çıkartabilmektedir. Bu aşamada yapılacak erken tespitlerin maliyet açısından da kazanımları büyük olabilmektedir.

SD Metrics

Coverity (http://www.coverity.com/)

Java’nın yanı C++ ve C program kodları üzerinden çalışabilen ticari ve oldukça kapsamlı bir kod analiz aracıdır. Analiz sonuçlarının yanı sıra bazı otomatik düzeltmeler de yapabilen program yazılım dünyası tarafından çok büyük maliyetli ve kapsamlı projelerde kullanılmaktadır. Bu programın diğer bir önemli özelliği de, statik analizin yanı sıra çalışma esnasında dinamik analizleri de yapabilmesidir. Aşağıda Coverity programı ile üretilmiş örnek bir bağımlılık grafiği verilmiştir.

Coverity

Visul Studio Kod Metrikleri (Code Metrics)

Kod metrikleri, Visual Studio içinde yer alan kaynak kodları incelemek ve çeşitli ölçülere göre yazılımı derecelendirmek için kullanılan matematiksel ve istatistiksel yöntemlerdir. Kod metrikleri, bir projenin sınıflarını, modüllerini ve namespacelerini, çeşitli ölçülerle değerlendirerek potansiyel sorun kaynaklarını vurgular.

  • Lines of Code
  • Class Coupling
  • Depth of Inheritance,
  • Cyclomatic Complexity
  • Maintainability Index

Kod Metrikleri, Solution Explorer’da bir projeye veya solution üzerine sağ tıklayıp “Calculate Code Metrics” diyerek veya Analyze menüsünden “Calculate Code Metrics For Solution / Project” ile hesaplanabilir.

Codemetrics

Lines of Code

Lines of Code, bir metoddaki işletilebilir kod satır sayısını gösterir. Alfabe dışı karakterler, commentler, tip ve namespace tanımları bu hesaplamanın dışında kalır. Çok yüksek bir değer, bir tipin veya metodun çok fazla iş yaptığı, bu yüzden de bölünmesi gerektiği anlamına gelir.

Lines of code

Class Coupling

Bu metrik; sınıf seviyesinde, parametreler, yerel değişkenler, dönüş tipleri, method çağırımları, generic ilklemeler, base sınıflar, arayüz implementasyonları vb. aracılığıyla diğer sınıflarla olan bağlantı sayısını ölçer. Kısaca bu metrik bir sınıfın bağlı olduğu sınıf sayısını gösterir. Bu sayının mümkün olduğunca az olması beklenir. Çünkü yüksek coupling değerleri, bir tasarımın diğer sınıflara bağımlılıkları yüzünden, yeniden kullanılmasının ve bakımının güç olduğu anlamına gelir.
classcoupling

Depth of Inheritance

Kalıtım derinliği, bir sınıfın, kalıtım ağacında o sınıfın üst düğümünden köke kadar olan sınıfların sayısını gösterir. Hiyerarşi ne kadar derinleşirse, hangi metodların veya alanların nerelerde tanımlandığını veya yeniden tanımlandığını takip etmek de zorlaşır. Çok derin kalıtım ağaçları, uygulamanın testinin ve bakımının karmaşıklığını arttırır.
Depth of Inheritance

Cyclomatic Complexity

Cyclomatic Complexity programdaki birbirinden farklı kod akışlarının sayısıdır. Daha basitçe açıklamak gerekirse, programdaki karar noktaları olan if bloklarının, do, while, foreach ve for döngülerinin ve switch case bloklarının sayısıdır. Yüksek cyclomatic completixy değerine sahip olan kodların test ve bakımı zor olmaktır. Çünkü bu kodlarda test edilebilecek çok sayıda farklı akış vardır.

Cyclomatic Complexity

Cyclomatic Complexity(CC) değerini hesaplamak için aşağıdaki gibi basit bir yol izlenebilir.

  1. Metodun akışına CC= 1 değeri ile başla.
  2. Her bir if,while,repeat, for, and , or anahtar kelimeleri veya eşdeğerleri için CC’ye 1 ekle
  3. Switch’teki her bir case için CC’ye 1 ekle

Metodlar için cyclomatic complexity değerleri ve riskleri belirtilmiştir. Cyclomatic complexity değeri ne kadar yüksekse metodun karmaşıklığı da o kadar fazladır.

cyclomatic complexity tablo

Maintainability Index

Sınıf üyeleri veya tipler seviyesinde kod bakımının kolaylığına gösteren bu değişken 0-100 arasında bir değer alır. Bu değerin yüksek olması programın sürdürebilirlik seviyesinin yüksek olduğu anlamına gelir. Namespace veya assembly seviyesindeki maintainability index, o namespace veya assembly içerisindeki bütün tiplerin maintainability indexlerinin ortalamasıdır. Bu metrik, Halstead Volume, Cyclomatic Complexity ve Lines of Code metrikleri bir araya getirilerek oluşturulmuştur. Halstead Volume, kullanılan işlenen (operand) ve işlemcilerin (operator) sayısıyla ilgili bir metriktir. Maintainability index için kullanılan denklem aşağıda verilmiştir.

—MI = 171 – 5.2 * log2 (HV) – 0.23 * (CC) – 16.2 * log2 (LOC)

—HV: Halstead Volume
—CC: Cyclomatic Complexity
LOC: Lines of Code

Maintainability index, kolay bir gösterimi olması için ikonlarla ifade edilmiştir. İkonlar için, değer aralıkları ve sürdürebilirlik seviyeleri aşağıdaki gibidir.

maintainability index

Kaynaklar

1. U. Erdemir, U.Tekin, F.Buzluca, “Nesneye Dayalı Yazılım Metrikleri ve Yazılım Kalitesi” Yazılım Kalitesi ve Yazılım Geliştirme Araçları Sempozyumu (YKGS08), İstanbul, 2008.

2. Doç Dr. Feza Buzluca, İTÜ, BLG468E Object-Oriented Modeling and Design ders notları  http://ninova.itu.edu.tr/tr/dersler/bilgisayar-bilisim-fakultesi/2097/blg-468e/ekkaynaklar/

Enum Flag Özelliği

Enum, programlamada oldukça sık başvurulan, sayısal değerleri anlamlı bir şekilde isimlendirilerek kullanılabilmesini sağlayan yapıdır. Enum yapısı yaygın olarak her bir üyesinin tek bir değer taşıdığı hali ile kullanılır. Örneğin bir ev konum itibariyle tek bir şehirde yer alır. Bu durumda evin bulunduğu şehri bir enum yapısının tek bir üyesi ile aşağıdaki gibi gösterebiliriz:

public enum Sehirler {
   Ankara,
   Antalya,
   Istanbul,
   Kocaeli
}
ev.Konumu = Sehirler.Ankara;

Ancak bazen tek bir üye ifade için yeterli olmaz. Örneğin bir evin sahip olabileceği özellikler enum üyeleri ile temsil edildiğinde birden fazla özellik aynı evde bulunabilir. Bu durumda evin sahip olduğu özellikleri nasıl göstereceğimiz sorusu gündeme gelir.

public enum Ozellikler {
   Balkonlu,
   Klimali,
   Panjurlu,
   Otoparkli
}

Bu problemi çözmek için akla iki yöntem gelmektedir:

  • Olası tüm kombinasyonlar enum içinde üye olarak eklenir.
    public enum Ozellikler {
      Balkonlu,
      Klimali,
      Panjurlu,
      Otoparkli,
      BalkonluKlimali,
      BalkonluPanjurlu,
      BalkonluOtoparkli,
      KlimaliPanjurlu,
      KlimaliOtoparkli,
      PanjurluOtoparkli,
      BalkonluKlimaliPanjurlu,
      BalkonluKlimaliOtoparkli,
      BalkonluPanjurluOtoparkli,
      KlimaliPanjurluOtoparkli,
      BalkonluKlimaliPanjurluOtoparkli
    }
    
  • Evin sahip olduğu özellikler liste olarak tutulur
    ev.Ozellikleri = { Ozellikler.Balkonlu, Ozellikler.Klimali }
    

Birinci yöntem az sayıda özellik için kullanılabilir olsa da özellik sayısının fazla olması durumunda ortaya çok sayıda kombinasyon çıkacağından kullanılması zordur. İkicinci yöntem çok daha mantıklı gözükse de verilerin saklanması noktasında veritabanında fazladan tablo oluşturulması ve verinin okunup yazılması noktasında fazladan kodlama gerektirecektir.

Enum yapılarında kullanılan Flag özelliğine tam da bu noktada ihtiyaç duyulmaktadır. Flag özelliği arka planda enum üyeleri üzerinde mantıksal işlemler yaparak bize çoklu değerler kullanma imkanı verir. Flag özelliğinin kullanımı aşağıdaki gibidir:

[Flag]
public enum Ozellikler {
   Balkonlu = 1, 	// 2^0
   Klimali = 2, 	// 2^1
   Panjurlu = 4, 	// 2^2
   Otoparkli = 8 	// 2^3
}

Flag özelliğinin kullanımında dikkat edilecek olan nokta enum üye değerlerinin 1, 2, 4, 8 … şeklinde 2’nin üsleri olacak şekilde atanmasıdır. Burada amaç ikili düzende yapılacak olan mantıksal işlemlerle tüm kombinasyonları elde etmektir.

Bir enum yapısındaki üyeler ile elde edilebilecek tüm kombinasyonların sayısı n üye sayısı olmak üzere 2n-1’dir. (Hiçbir üyenin dahil olmadığı seçeneği yani boş kümeyi de düşünürsek sayı 2n olur.) 2n adet seçeneği ikilik düzende n basamak ile ifade edebiliriz.

Üye 10’luk Düzen 2’lik Düzen
Boş küme 0 0000
Balkonlu 1 0001
Klimali 2 0010
BalkonluKlimali 3 0011
Panjurlu 4 0100
BalkonluPanjurlu 5 0101
KlimaliPanjurlu 6 0110
BalkonluKlimaliPanjurlu 7 0111
Otoparkli 8 1000
BalkonluOtoparkli 9 1001
KlimaliOtoparkli 10 1010
BalkonluKlimaliOtoparkli 11 1011
PanjurluOtoparkli 12 1100
BalkonluPanjurluOtoparkli 13 1101
KlimaliPanjurluOtoparkli 14 1110
BalkonluKlimaliPanjurluOtoparkli 15 1111

Flag özelliğinin kodlama içerisinde kullanımı ise oldukça basittir. Değişkene atanmak istenen enum üyeleri mantıksal OR işlemine sokulur. Böylece enum değişkeni üzerinde istenen kombinasyonun saklanması sağlanır.

ev.Ozellikleri = Ozellikler.Balkonlu | Ozellikler.Otoparkli;

Elimizdeki enum değişkeninin belirli bir enum üyesini ya da belirli bir kombinasyonu barındırıp barındırmadığını belirlemek için HasFlag metodu kullanılır. HasFlag metodu değişken içerisinde, parametre olarak verdiğimiz enum üye(ler)ini barındırıyorsa geriye true değerini döner.

ev.Ozellikleri = Ozellikler.Balkonlu |
                 Ozellikler.Otoparkli |
                 Ozellikler.Klimali;
ev.Ozellikleri.HasFlag(Ozellikler.Klimali);	//true
ev.Ozellikleri.HasFlag(Ozellikler.Panjurlu);	//false
ev.Ozellikleri.HasFlag(Ozellikler.Balkonlu | Ozellikler.Otoparkli); //true
ev.Ozellikleri.HasFlag(Ozellikler.Balkonlu | Ozellikler.Panjurlu);  //false

Flag özelliğinin en güzel yanlarından birisi de ToString() metodu ile enum değişkeni içerisindeki tüm enum üyelerinin CVS formatında virgülle ayrılarak yazılıyor olmasıdır.

ev.Ozellikleri = Ozellikler.Balkonlu |
                 Ozellikler.Otoparkli |
                 Ozellikler.Klimali;
ev.Ozellikleri.ToString();	// Bankonlu, Otoparkli, Klimali

Bunun yanında enum tipi içerisinde bulunan Parse metodu içerisinde çoklu enum isimlerini virgül ile ayırarak verildiğinde ilgili değerlerin otomatik olarak atanması mümkündür.

ev.Ozellikleri = (Ozellikler)Enum.Parse(typeof(Ozellikler),
                                        "Bankonlu, Otoparkli");

Enum için izin verilen veri tipleri byte, sbyte, short, ushort, int, uint, long ve ulong’dur. Bu veri tiplerinden ulong kullanılması durumunda enum içinde maksimum 64 değer üye tanımlanabilir.

public enum WebAgentPermission : ulong
{
	RuleGroup = 1,						//2^0
	Location = 2,						//2^1
	VolumeStatistics = 4,				//2^2
	...
	UserPassword = 256,					//2^8
	...
	AuditLogs = 65536,					//2^16
              ...
	WebAgentReports = 4294967296,				//2^32
	...
	PespectiveSearch =  281474976710656,		//2^48
	...
	DictionaryManager = 9223372036854775808         //2^63
}

photo

Tip Dönüşümü

Bundan yaklaşık 4 ay önce halen çalışmakta olduğum işime henüz yeni girmiş ve geliştirilen yazılımları inceleyip anlamaya çalışıyordum ki karşılaştığım bir kod parçası beni hayretler içinde bırakmıştı. Yazılımcı arkadaşımızın C#’da TryParse isimli bir metodun varlığından haberi olmasa gerek söz konusu metodu kendisi yazmış ve bunu da pek çok yerde kullanmıştı. Veri tipleri ve tipler arasındaki dönüşüm C#’da en temel konular arasında olsa da çoğu zaman özellikle de yazılıma yeni başlayanlar tarafından göz ardı ediliyor ve ortaya karmaşık yapılar, düşük performanslı yazılımlar çıkıyor.

Değişkenler bir programlama dilinde temel verileri saklamak ve bu verileri sonradan kullanmak için kullanılan bellek bölgeleridir. C# dilinde genel olarak bir değişken tanımlaması aşağıdaki gibi olmaktadır.

<veri tipi> <veri adı>;

C# dilinde temel olarak veri tipleri ikiye ayrılır. Bunlar önceden tanımlanmış veri tipleri ve kullanıcı tarafından tanımlanmış veri tipleridir. Önceden tanımlanmış veri tipleri de kendi arasında referans tipi (reference types) ve değer tipi (value type) olmak üzere ikiye ayrılır.

Değer tipli değişkenlerin boyutu programın derlenmesi aşamasında bellidir ve bellekte stack (yığın) adı verilen bölgede doğrudan verinin kendisi tutulur. Referans tipli değişkenlerin ise boyutu programın derlenmesi aşamasında belli değildir. Bu sebeple veri stack üzerinde değil yine bellekte heap adı verilen başka bir bölgede tutulur. Stack üzerinde ise, veriye işaret eden (adres bilgilerini tutan) bir değer tipi saklanır.

Değer tipli değişkenlerde, değişkene ilk değer atanmadığında değişken otomatik olarak ilk değerini belirler. Örneğin int değişkenine 0, bool değişkenine false şeklinde atama yapılır. Referans tipli değişkenler oluşturulduğunda ve ilk değer ataması yapılmadığında ise değeri otomatik olarak null olur. Değer tipli bir değişken başka bir değer tipli değişkene eşitlendiğinde Stack bölgesinde bir veri kopyalama işlemi oluşur. Fakat referans tipli değişkenlerde, aynı veriyi gösteren farklı bir referans oluşturulur.

C# tip-korumalı bir dildir. Başka bir deyişle C# dili programda kullanılacak değişkenlerin tutacağı veri tiplerini kesin sınırlarla birbirinden ayırır. Dolayısıyla, bir değişken bildirimi yapılırken, o değişkenin veri tipi kesinlikle belirtilir. Daha sonra o değişkene atanan veriler, belirtilen veri tipinin dışına çıkamaz.

C# Tipi .NET Tipi Uzunluk(Byte) Değer Aralığı
byte Byte 1 0 – 255
sbyte SByte 1 -128 – 127
short Int16 2 -32768 – 32767
ushort UInt16 2 0 – 65535
int Int32 4 -2147483648 – 2147483648
uint UInt32 4 0 – 4294967295
long Int64 8 -1020 – 1020
ulong UInt64 8 0 – 2×1020
float Single 4 ±1.5 x 10-45 – ±3.4×1038
double Double 8 ±5.0×10-324 – ±1.7×10308
decimal Decimal 16 ±1.5×10-28 – ±7.9×1028
char Char 2
bool Boolean 1 true, false

Bir değişkenin tuttuğu verinin başka bir veri tipine dönüştürülmesine casting (çevrim) denir. C# dilinde çevirme işlemi sadece belirli özellikteki veri tipleri arasında yapılabilmektedir. Bunlar;

  • Sayısal veri tipleri
  • Kalıtım hiyerarşisi içindeki sınıflar
  • Aynı arayüzü uygulayan sınıflar
  • Farklı ama birbirleri için dönüşüm operatörleri tanımlanmış sınıflar

Çevrim işlemi, implicit (bilinçsiz) ve explicit (bilinçli) olmak üzere 2 farklı şekilde yapılabilir. C# ta genel olarak veri kaybına yol açma olasılığı olmayan dönüştürmeler (bellekte daha küçük bir alan kaplayan veri tipinden daha büyük bir alan kaplayan veri tipine dönüştürme) derleyici tarafından implicit olarak gerçekleştirilir.

int a  = 123;
long b;
b = a;  // b = 123

Implicit olarak dönüştürme yapılabilecek veri tipleri aşağıdaki tabloda listelenmiştir.

Kaynak Hedef
sbyte short, int, float, long, double, decimal
byte short, ushort, int, uint, long, ulong, float, double, decimal
short int, long, float, double, decimal
ushort int, uint, long, ulong, float, double, decimal
int long, float, double, decimal
uint long, ulong, float, double, decimal
long, ulong float, double, decimal
char ushort, int, uint, long, ulong, float, double, decimal
float double

Diğer taraftan veri kaybına yol açma olasılığı olan dönüştürmeler (bellekte daha büyük bir alan kaplayan veri tipinden daha küçük bir alan kaplayan veri tipine dönüştürme) tür dönüştürme operatörü kullanılarak explicit olarak yapılabilmektedir. Bu tür dönüştürmeler tür dönüştürme operatörü kullanılmadan yani implicit olarak yapılırsa hata ile karşılaşılır.

int a;

long b = 456;

a = b;        // HATA

a = (int)b;   // a = 456

double c = 12.34;
a = (int)c;   // a = 12

Checked ve Unchecked Blokları

Explicit dönüştürmede dikkat edilecek önemli bir husus dönüştürme sonrası veri kaybının olabileceğidir. Derleyici varsayılan olarak bu durumda hata üretmez. Veri kaybı olduğunda programın hata vermesi istenen kısımlar checked blokları içine alınır. Benzer şekilde veri kaybı olduğunda programın hata vermesi istenmeyen kısımlar ise unchecked (varsayılan durum) blokları içine alınır.

int i=256;
int a=300;
byte b, c;

checked{
   b=(byte)i;
   unchecked{
      c=(byte)a;
   }
}

Tip Dönüştürme Operatörleri

Implicit ve Explicit olarak birbirine dönüşümü mümkün olmayan iki sınıfın birbirine dönüşümünü mümkün kılmak için tip dönüştürme operatörleri kullanılır.

public class Inch{
   public decimal Length { get; set; }
   public static implicit operator Cm(Inch i){
      Cm c = new Cm();
      c.Length = i.Length * 2.54M;
      return c;
   }
}

public class Cm{
   public decimal Length { get; set; }
   public static explicit operator Inch(Cm c){
      Inch i = new Inch();
      i.Length = c.Length / 2.54M;
      return i;
   }
}

Inch i1 = new Inch();
i1.Length = 5;
Cm cm1 = i1;          // Implicit casting

Cm cm2 = new Cm();
cm2.Length = 3;
Inch i2 = (Inch)cm2;  // Explicit casting

Boxing ve Unboxing

Değer tipinden bir değişkenin, object türüne implicit dönüştürülmesine boxing işlemi denir. Boxing işleminin tam tersi olan, objet türünden bir değişkenin, değer tipine explicit dönüştürülmesine ise unboxing işlemi denir.

int i1 = 123;

object o1 = i1;   // boxing

int i2 = (int)o1; // unboxing

Is ve As Operatörleri

Boxing ve Unboxing işlemleri veya sıradan bir tip dönümüşümü yapılırken değişkenin tipini dönüşüm yapılmak istenen tiple is operatörü ile karşılaştırarak çevrimin doğru olup olmadığı kontrol edilebilir.

DerivedType derivedObj = new DerivedType();

if(derivedObj is BaseType){
   BaseType baseObj = (BaseType)derivedObj;
}

As operatörü is operatöründen farklı olarak kontrol işlemini dönüştürme işleminden önce değil sonra yapılmasını sağlar. As operatörü ile yapılan dönüştürme işleminde doğru olmayan bir dönüşüm yapıldıysa hata üretilmez ancak değişken null değerini alır.

DerivedType derivedObj = new DerivedType();
BaseType baseObj = derivedObj as BaseType;
if(baseObj != null){

}

GetType ve typeof

.NET içinde herhangi bir veri tipi ile işlem yapmak için kullanılabilecek Type isimli sınıf bulunmaktadır.  Type sınıfından bir nesne elde etmek için ise başlıca iki yöntem vardır: GetType metodu ve typeof operatörü.

GetType metodu .NET’de her yapının doğrudan ya da dolaylı olarak türediği object sınıfı içinde tanımlanmış ve dolayısıyla her yapıya miras olarak aktarılmış bir metodtur. typeof operatörü ise parametre olarak aldığı tür adından türe ilişkin ilgili Type nesnesini oluşturur. Aradaki en büyük fark GetType nesneler üzerinde çalışırken, typeof sınıflar üzerinde çalışır.

MyClass c = new MyClass();

Type t1 = c.GetType();
Type t2 = typeof(MyClass);

Console.WriteLine(t1 == t2);

Int32.Parse

String tipindeki bir değişkeni int tipine dönüştürmek için kullanılan static  Int32.Parse metodunun 3 adet Exception’ı bulunur. Bunlar ArgumentNullException, FormatException ve OverflowException‘dır.

  • ArgumentNullException: Giriş değeri null olduğu zaman gerçekleşir.
  • FormatException: Giriş değeri doğru formatta olmadığı zaman gerçekleşir. Örneğin; alfanümerik bir değer gibi.
  • OverflowException: Giriş değeri Int32 sınırlarını aştığında gerçekleşir.
string metnim1 = null;
string metnim2 = "123.456";
string metnim3 = "12345678910111213141516";
string metnim4 = "123456";
int sonuc;

sonuc = Int32.Parse(metnim1); // sonuc = ArgumentNullException
sonuc = Int32.Parse(metnim2); // sonuc = FormatException
sonuc = Int32.Parse(metnim3); // sonuc = OverflowException
sonuc = Int32.Parse(metnim4); // sonuc = 123456

Convert.ToInt32

Convert.ToInt32 metodunun Int32.Parse’tan en önemli farkı, yalnızca string verileri Int32 türüne çevirmek değil, bunların dışındaki veri tiplerini de çevirebiliyor olması geliyor.

İkinci önemli fark ise Int32.Parse’ın aksine 2 exception’a sahip olması. Bunlar FormatException ve OverflowException‘dır. Convert.ToInt32 giriş verisinin null olması durumunda hata fırlatmak yerine geriye 0 değeri döndürür.

string metnim1 = null;
string metnim2 = "123.456";
string metnim3 = "12345678910111213141516";
string metnim4 = "123456";
int sonuc;

sonuc = Convert.ToInt32(metnim1); // sonuc = 0
sonuc = Convert.ToInt32(metnim2); // sonuc = FormatException
sonuc = Convert.ToInt32(metnim3); // sonuc = OverflowException
sonuc = Convert.ToInt32(metnim4); // sonuc = 123456

Int32.TryParse

Verilen string değer int tipine dönüştürülebiliyorsa geriye true değeri dönülerek işlem gerçekleştirilir. Aksi halde hata fırlatılmaz sonuç olarak 0 üretilir ve geriye false değer dönülür. Bu sebeple riskleri en aza indirdiğinden diğer dönüştürme metodlarına göre daha avantajlıdır.

string metnim1 = null;
string metnim2 = "123.456";
string metnim3 = "12345678910111213141516";
string metnim4 = "123456";
int sonuc;

bool durum = Int32.TryParse(metnim1, out sonuc); // sonuc = 0, durum = false
bool durum = Int32.TryParse(metnim2, out sonuc); // sonuc = 0, durum = false
bool durum = Int32.TryParse(metnim3, out sonuc); // sonuc = 0, durum = false
bool durum = Int32.TryParse(metnim4, out sonuc); // sonuc = 123456, durum = true

Tip Dönüştürme Kuralları

  1. Tamsayı türlerinden tamsayı türlerine tür dönüştürme operatörü ile dönüşüm yapılırken gerçekleşecek olay, checked ya da uncheckeddurumda olup olmamaya göre değişir.
    1. Eğer checked durum içerisinde bulunuluyorsa, programın çalışma zamanı sırasında kontrol yapılır. Dönüştürülecek türdeki değer, dönüştürmenin yapıldığı türün sınırları içerisinde değilse, System.OverflowException türünden hata fırlatılır.
    2. Eğer unchecked durum içerinde bulunuluyorsa, sayınının yüksek anlamlı bitleri atılacak biçimde dönüştürme yapılır. Eğer, büyük işaretli türden küçük işaretsiz türe dönüştürme söz konusuysa, yüksek anlamlı bitler atıldıktan sonra kalan kısım işaretli olarak yorumlanır. Eğer küçük işaretli türden büyük işaretsiz türe dönüştürme yapılıyorsa, büyük ürün yüksek anlamlı bitleri işaret bitiyle doldurulur ve elde edilen değer işaretsiz olarak yorumlanır.
  2. decimal türden diğer tamsayı türlerine dönüştürme yaparken,sayının noktadan sonraki kısmı atılır. Elde edilen tam kısım, hedef türün sınırları içerisine sığmıyorsa, ister checked isterse unchecked durumda olunsun System.OverflowException oluşur.
  3. float ya da double türünden tamsayı türlerine operatör ile yapılan dönüştürmede, oluşacak durum checked ya da uncheckeddurumunda olmaya göre değişir.
    1. Eğer checked durumda bulunuluyorsa, noktadan sonraki kısım atıldıktan sonra oluşan değer, hedef türün sınırları içerisinde kalıyorsa işlem başarı ile yürütülür. Fakat oktalı kısım atıldıktan sonra oluşan değer hedef türün sınırları içerisine sığmıyorsa System.OverflowException oluşur.
    2. Eğer unchecked durumda bulunuluyorsa, ve noktadan sonraki kısım atıldıktan sonra hedef türün sınırları içerisinde kalınıyorsa problem oluşmaz. Fakat eğer oluşan deeğr hedef türün sınırları içerisinde kalmıyorsa, dönüştürmeden hangi değerin elde edileceği belirsiz (unspecified) bırakılmıştır.
  4. double türden float türüne dönüştürme yapıldığında hata, mantis kısmında ya da magnitute kısmında oluşabilir. Eğer mantis kısmında bir hata oluyorsa duyarlılık en yakın float duyarlılıkla ifade edilir. Eğer magnitute hatası oluşuyorsa dönüştürmeden duruma göre pozitif ya da negatif sonsuz elde edilir.
  5. float ve double türden decimal türüne yapılan dönüştürmelerde eğer bir magnitute hatası söz klonusu ise System.OverflowException oluşur, eğer mantis hatası söz konusu ise decimal türüne en uygun ifade dönüştürme sonucu elde edilir.
  6. decimal türden float ve double türüne dönüştürme yapıldığında sayı, en yakın float ya da double sayı ile temsil edilir. Fakat eğer bir magnitute hatası söz konusu olursa System.OverflowException oluşur.

SQL ROW_NUMBER() Fonksiyonu ile Sayfalama

ASP.NET uygulamalarında veriyi listelerken ihtiyaç duyulan yöntemlerden birisi de sayfalamadır. Özellikle listelenecek veri sayısı yeterince fazla olduğunda sayfalama kaçınılmaz olarak ortaya çıkmaktadır. ASP.NET bu amaçla kullanıcılarına birtakım kontroller üzerinden sayfalama imkanı sunsa da verinin tamamını çekip viewstate üzerinde saklaması dolayısıyla çoğu zaman performans kaybına yol açmaktadır.

Bu noktada SQL ROW_NUMBER() fonksiyonu kullanıcılara kendi geliştirecekleri sayfalama işleminde aynı anda sadece görüntülenecek veriyi seçme imkanı sunmaktadır. SQL ROW_NUMBER() fonsiyonu temel olarak SELECT sorgusu ile elde edilen tabloya 1’den başlayan ve 1’er artarak sıralı bir şekilde devam eden yeni bir kolon ekler.

SQL ROW_NUMBER() fonksiyonu ile yapılacak örnek bir sayfalama işlemi için Northwind veritabanında yer alan Products tablosu kullanılarak aşağıdaki Stored Procedure oluşturulmuştur.

CREATE PROCEDURE [dbo].[SelectProducts]
   @PAGE_SIZE int,
   @PAGE_NUMBER int
AS
   BEGIN
   SET NOCOUNT ON;
      BEGIN
      WITH TEMP as
      (
          SELECT TOP (@PAGE_SIZE*@PAGE_NUMBER+1)
          ROW_NUMBER() OVER (ORDER BY P.ProductID) as RowNumber,
          P.ProductID,
          P.ProductName,
          S.CompanyName,
          C.CategoryName,
          P.QuantityPerUnit,
          P.UnitPrice,
          P.UnitsInStock,
          P.UnitsOnOrder,
          P.ReorderLevel
          FROM dbo.Products P
          JOIN dbo.Categories C on P.CategoryID = C.CategoryID
          JOIN dbo.Suppliers S on P.SupplierID = S.SupplierID
      )
      SELECT    TOP (@PAGE_SIZE*@PAGE_NUMBER+1) *
      FROM TEMP
      WHERE RowNumber between @PAGE_SIZE*(@PAGE_NUMBER-1)+1 and @PAGE_SIZE*@PAGE_NUMBER+1;
      END
END

Yukarıdaki Stored Procedure @PAGE_SIZE ve @PAGE_NUMBER olmak üzere iki parametre almaktadır. Bu parametrelerden @PAGE_SIZE her bir sayfada listelenecek veri sayısını, @PAGE_NUMBER ise listelenmek istenen sayfa numarasını temsil etmektedir. Sorguda dikkat edildiği üzere @PAGE_SIZE+1 adet veri seçilmektedir. Bunun nedeni ise arayüzde bir sonraki sayfanın varlığını kontrol etmektir.

Verilerin listeleneceği web form arayüzü için aşağıdaki yapı kullanılmıştır.

<asp:HiddenField ID="hfPageSize" runat="server" Value="10"/>
<asp:HiddenField ID="hfPageNumber" runat="server" Value="1"/>
<table>
    <tr>
        <td colspan="9" class="main-header">Products</td>
    </tr>
    <tr>
        <td colspan="9" class="paging">
            <asp:LinkButton ID="btPrevious" runat="server" Visible="false" onclick="btPrevious_Click"><< Previous</asp:LinkButton>
            <asp:LinkButton ID="btNext" runat="server" Visible="false" onclick="btNext_Click">Next >></asp:LinkButton>
        </td>
    </tr>
    <tr class="header">
        <td>Product ID</td>
        <td>Product Name</td>
        <td>Company Name</td>
        <td>Category Name</td>
        <td>Quantity Per Unit</td>
        <td>Unit Price</td>
        <td>Units In Stock</td>
        <td>Units On Order</td>
        <td>Reorder Level</td>
    </tr>
    <asp:Repeater ID="rpProducts" runat="server">
        <ItemTemplate>
            <tr class="item">
                <td><%# Eval("ProductID") %></td>
                <td><%# Eval("ProductName") %></td>
                <td><%# Eval("CompanyName") %></td>
                <td><%# Eval("CategoryName") %></td>
                <td><%# Eval("QuantityPerUnit")%></td>
                <td><%# Eval("UnitPrice")%></td>
                <td><%# Eval("UnitsInStock")%></td>
                <td><%# Eval("UnitsOnOrder")%></td>
                <td><%# Eval("ReorderLevel")%></td>
            </tr>
        </ItemTemplate>
    </asp:Repeater>
</table>

Veriler ASP.NET Repeater kontrolü ile bir tablo yapısında sayfada listelenmektedir. Listelenen verilerin üzerinde bir önceki ve bir sonraki sayfalara geçmek için kullanılacak iki adet ASP.NET LinkButton kontrolü bulunmaktadır. Son olarak sayfalama işleminde parametre olarak sayfada listelenecek veri sayısını ve görüntülenmekte olan sayfa numarasını tutacak iki adet ASP.NET HiddenField kontrolü yer almaktadır.

Bu aşamdan sonra yapılması gereken ASP.NET HiddenField kontrollerinde tutulan parametreleri ASP.NET LinkButton kontrolleri vasıtası ile yönetmek ve gerekli durumlarda veritabanında yer alan ilgili Stored Procedure çağrısı yaparak verileri listelemektir.

protected void Page_Load(object sender, EventArgs e)
{
    if (!IsPostBack)
    {
        //Verileri listele
        DataBind();
    }
}

protected void btNext_Click(object sender, EventArgs e)
{
    //Sayfa numarasını bir arttır
    int pageNumber = Convert.ToInt32(hfPageNumber.Value);
    hfPageNumber.Value = (pageNumber + 1).ToString();
    //Verileri listele
    DataBind();
}
protected void btPrevious_Click(object sender, EventArgs e)
{
    //Sayfa numarasını bir azalt
    int pageNumber = Convert.ToInt32(hfPageNumber.Value);
    hfPageNumber.Value = (pageNumber - 1).ToString();
    //Verileri listele
    DataBind();
}
private void DataBind()
{
    //Sayfada listelenecek veri sayısının elde edilmesi
    int pageSize = Convert.ToInt32(hfPageSize.Value);
    //Görüntülenecek sayfa numarasının elde edilmesi
    int pageNumber = Convert.ToInt32(hfPageNumber.Value);

    //İlgili sayfa için verilerin elde edilmesi
    List list = DB.GetInstance().SelectProducts(pageSize, pageNumber);
    //Sayfada listelenecek veri sayısından fazla (+1) veri var mı?
    if (list.Count &gt; pageSize)
    {
        rpProducts.DataSource = list.Take(pageSize);
        btNext.Visible = true; //Sonraki sayfa var
    }
    else
    {
        rpProducts.DataSource = list;
        btNext.Visible = false; //Sonraki sayfa yok
    }
    rpProducts.DataBind();

    //Sayfa numarası 1'den büyük ise önceki sayfa var aksi halde yok
    btPrevious.Visible = (pageNumber &gt; 1) ? true:false;
}

İlk Sayfa

5. Sayfa

Son Sayfa

Yani Programlama Jargonları

Geçtiğimiz günlerde karşılaşmış olduğum “New Programming Jargon” adlı yazıda programlama dünyasında çok sık rastlanan, yazılımcılar tarafından bilinçli ya da bilinçsiz olarak kullanılan çeşitli özellikler listelenmiş ve bunlara yazılım dünyasında ortak bir jargon oluşturmak adına çeşitli isimler verilmişti. Benim keyifle okuduğum bu yazıda yer alan hoşuma giden 10 özelliği aşağıda belirttim. Diğer tüm özellikler için ilgili yazıya aşağıdaki bağlantıdan ulaşabilirsiniz.

http://www.codinghorror.com/blog/2012/07/new-programming-jargon.html

1. Yoda Conditions

Genel olarak koşul ifadelerinde test edilecek değişken sol tarafta, karşılaştırma yapılacak değer ise sağ tarafta yazılır.
if (var == 5)
Programlama açısından bu durumun tersi de çalışmaya engel olmayıp bu tarz kullanımlar “Yoda Conditions” olarak adlandırılmış.
if (5 == var)

2. Pokemon Exception Handling

Hatalar yazılımların kaçınılmaz bir gerçeğidir. Her bir hata türü için ilgili bir sınıf var olmasına karşılık işin kolayına kaçıp hata ayıklama esnasında bu sınıfların türediği temel hata sınıfını kullanmak “Pokemon Exception Handling” olarak adlandılmış.
try
{
}
catch (Exception exp)
{
}

3. Egyptian Brackets

İlk kez Kernighan ve Ritchie tarafından çıkardıkları “The C Programming Language” adlı kitapta kullanılan, başlangıç parantezinin ilgili satırın sonunda yer alması durumu Mısır kabartmalarında kullanılan figürlerden esinlenerek “Egyptian Brackets” olarak adlandırılmış.
if (a == b) {

}

4. Stringly Typed

Genellikle parametre aktarımlarında, değişkenleri kendi veri tipi ile kullanmak yerine, her bir veri tipine kolayca dönüştürülebilir özelliğinden olsa gerek string veri tipi ile kullanılması durumu “Stringly Typed” olarak adlandırılmış. Bu durumun kodun anlaşılırlığını azaltmakla birlikte hataların ayıklanmasını da zorlaştırmaktadır.

5. Baklava Code

Yazılımı katmanlar halinde geliştirmek kaliteli bir yazılım için olmazsa olmazlardandır. Ancak bu durumu abartıp çok sayıda katman yaratmak kodu karmaşıklaştırdığı gibi yönetilebilirliği de azaltacaktır. Bu tarz yapılar “Baklava Code” olarak adlandırılmış.

6. Hydra Code

Çok sayıda hatadan oluşan ve her bir hatanın çözümünde yeni hatalar ortaya çıkan kod parçaları hydra efsanesinden esinlenerek “Hydra Code” olarak adlandırılmış.

7. Smurf Naming Convention

Yazılımda değişkenlere anlamlı isimler verilirken genellikle değişkenlerin ne ile alakalı olduğunu belirtmek için isimlerin başına (ya da sonuna) ortak bir ön isim eklenir. Bu durum “Smurf Naming Convention” olarak adlandırılmış. Ör: SmurfAccountView, SmurfAccountDTO, SmurfID, SmurfAccountController, SmurfOrderHistory, SmurfHistoryMatch, SmurfHistoryReviewView, SmurfHistoryReportingView

8. Bicrement

Değişkenlere +1 değerinin eklenmesi “Increment” olarak ifade edildiği gibi +2 değerinin eklenmesi de “Bicrement” olarak adlandırılmış.

9. Mad Girlfriend Bug

Koda bakıldığında herşeyin düzgün olduğu görüldüğü halde çalışma esnasında beklenenden farklı davranan durumlar “Mad Girlfriend Bug” olarak adlandırılmış. Gerçek hayatta da olduğu gibi çözümü en zor hatalar bu tarz durumlarda olsa gerek:)

10. Jenga Code

Yazılımdan ufak bir bölümün çıkarılması halinde çok sayıda hata oluşarak yazılımın çalışmaz duruma gelmesi “Jenga Code” olarak adlandırılmış.