C# Exception Yapısı ve Custom Exception

5 Şub

Yazılım geliştirici olarak yazdığımız kodlarda oluşabilecek istenmeyen durumlar ile başa çıkmak durumundayız. Aksi taktirde yazılımlarımız zamanla kullanılamaz hale gelebilir. İstisnai durumların oluşturulması veya oluşturulmaması üzerine zamanla bazı fikirler gelişmiştir.

Microsoft tarafından oluşturulan eski yönergelerde istisnai durumlar ile başaçıkabilmek için bazı yönlendirmeler bulunmaktadır. Bunlardan biri de temel Exception sınıfından türetilmiş SystemException ve ApplicationException şeklinde iki kategori oluşturarak istisnai durumları gruplamaya çalışmaktır.

ApplicationException

ApplicationException sınıfı System.Exception sınıfından türetilmiş bir istisnai durum bildirim türüdür. Bu türü, uygulamamızın iç yapısı ile alakalı istisnai durumlar oluştuğunda bildirimler oluşturmak amacıyla oluşturulmuştur. İstisnai durumlar bir hata veya bir uyarı olabilir. Uygulamamıza özel istisnai durum sınıflarına ihtiyaç duyduğumuzda ApplicationException sınıfından durumumuza özel yeni bir sınıf türetebiliriz. Özel istisna (custom exception) sınıfları oluşturma konusunda Microsoft tarafından oluşturulan kılavuzlarda tecrübe aktarımları mevcuttur.

SystemException

SystemException sınıfı da System.Exception sınıfından türetilmiştir. .Net Framework üzerinde CLR tarafından üretilen tüm istisnalar bu sınıf altında toparlanmıştır. Bu sınıf ile sisteme ait istisnai durum bildirimleri oluşturulmaktadır ve fetal error diye adlandırılan önemli hataların oluştuğu istisnai durumlarda kullanılırlar. Örneğin veritabanı bağlantı hataları, dosya hataları, bellek kullanım hataları oluştuğu durumlarda SystemException sınıfından türetilmiş olan sınıflar kullanılır.

İstisnai durumların kod ile ayırımı

Kodlama sırasında try-catch bloğunda istisnai durumun türüne göre tavrımızı belirleyebiliriz.

   try{
       var data = fileService.ReadFromFile();
   }
   catch(ApplciationException e){
       // Bu kısımdaki hata kontrolüm altında devam et...
   }
   catch(SystemException e){
       // Bu hata sistemsel bir sorundur log tut ve tekrar istisna gönder
       throw;
   }

SystemException türünde bir durum meydana geldiyse bu hatalar mutlaka log servisleri ile kayıt altına alınmalıdır ve görmezden gelinmemelidir.

Runtime esnasında oluşan hataları System, uygulama tarafında oluşan istisnaları Application olarak ayırmak mantıklı gibi görünebilir. Ancak bir istisnanın ölümcül(fetal) olarak değerlendirilmesi istisnanın içinde bulunduğu şartlara bağlıdır. Çalışma zamanında oluşan her hatanın ölümcül(fetal) olduğu söylenemeyeceği gibi framework dışındaki geliştiricilerin yazdığı uygulama istisnaların hepsinin göz ardı edilebilir olduğu söylenemez.

Örneğin FileNotFoundException durumu oluştuğunda her zaman programı kapatmanın anlamı yoktur. Bu durum kullanıcıya uygun bir mesaj ile iletilebilir. Hatta bazı dosyaların eksikliğinin öngörülebilmesi için faydalıdır bile denilebilir.

Bu nedenle bu başlangıç kılavuzu çıkmadı ve Microsoft da zaten çıkarmak için zorlamadı. Öte yandan şu anda .Net Framework’te bile ApplciaitonException sınıfından türetilmiş birkaç istisna bulabilirsiniz. Günümüzde yeni bir istisna türü oluşturmak isteyen biri bu iki kategoriyi kullanmak yerine Exception temel sınıfından yeni bir istisna sınıfı oluşturmaktadır. Yani System ve Application kategorisini kullanan pek yoktur.

Özel istisna türleri (custom exceptions) oluşturmak

Exception durumları hakkında kısa bir zaman yolculuğu yaptıktan sonra asıl konumuz olan özel istisna sınıflarının oluşturulmasına gelmiş bulunuyoruz.

Günümüzde geliştiricilerin kendine özel istisna türlerini oluşturmak için belli bir hiyerarşi oluşturduğunu görmek mümkündür. Örneğin:

Burada iş kurallarına ait tüm istisnalar BusinessRuleException altında toplanmıştır.

Peki bu durumda özel istisna sınıfları oluşturmak uygun bir yöntem midir? Ya da InvalidOperationException, ArgumentException gibi özel türleri mi kullanmak gereklidir? Bu iki sorunun cevabı istisnaları kimin kullanacağıdır. Kullanacak olan sizseniz özel istisnalar oluşturmak korkunç bir düşüncedir. Burada unutulmamalıdır ki istisnalar kodda istisnai bir durumu belirtmek için kullanılır. Yani beklenmeyen bir durumu anlatmak için kullanılır.

Özel istisnalar ile ilgili bir kod yapısı oluşturulduğunda aşağıdaki gibi bir durum meydana gelecektir.

public string CreateCustomer(string name, string email)
{
   try
   {
     /* Creating a customer */
   }
   catch (EmailIsNotUniqueException)
   {
       return "The email provided already registered: " + email;
   }
   catch (CustomerNameIsInvalidException)
   {
       return "Customer name is invalid: " + name;
   }
   catch (CustomerAddressIsInvalidException)
   {
       return "Customer address is invalid";
   }
}

Bu kod yapısı C# diline uygun olsa da, hatta kullanışlı görünse bile iyi bir kullanım şekli değildir. Çünkü burada program akışı kontrol edilirken istisnalar kullanılmıştır ve istisnaların kontrol akışını sağlamak gibi bir görevi yoktur. Yukarıda da bahsettiğimiz gibi istisnalar istenmeyen bir durumu belirtmek için kullanılır.

Yazdığınız kodu sadece siz kullanacaksanız özel istisna sınıfları türetmenize gerek yoktur. İstisnalar yazılımınızdaki beklenmedik hataları bildirir ve işlemi tamamen sonlandırmanıza olanak verir. Ayrıca geçersiz bir girdi parametresinde olağan dışı bir durum yoktur ve bu sadece basit bir doğrulama hatasıdır.

Kendi oluşturduğunuz istisnaları, yürütme yığınının en üst düzeyindeki try-catch bloğunda yakalamak uygun bir yöntem olacaktır. İstisnaların burada log kayıtları tutulabilir ve kullanıcıya bir uyarı mesajı gönderilebilir. Örneğin Web Api için kullanıcıya 500 mesajı verilebilir.

Özel istisna türleri (custom exceptions) ve harici kütüphaneler

Yazdığınız kodu sizin dışınızda başka geliştiriciler de kullanacaksa istisnai durumlar için farklı bir yol izlenebilir.

Yazdığınız kütüphanede ortaya çıkan beklenmedik istisnai durumları nasıl ele alacağınızı siz bilmesenizde kütüphenenizi kullanan geliştiriciler bunu biliyor olabilir. Örneğin bir FTP client uygulaması kuruyorsunuz ve ana makine client uygulamaya cevap vermiyorsa bir çok kez deneme yapabilirsiniz. Bu durumda client uygulama kendi içerisinde sürekli yeniden bağlanmayı denerse işin içinde çıkılamaz. Bunun yerine kütüphanenizi kullanan geliştiriciye bağlantı hatası fırlatıldığında geliştirici bu durumda ne yapacağını kestirebilir. Sonuçta bağlantı sağlanamaması durumu ile nasıl başa çıkacağını kütüphane kullanıcısı bilir. Bu gibi durumlara karşı her kullanıcının alacağı önlem farklı olabileceğinden bu istisnai durumun özel bir tür olarak diğer istisnai durumlardan ayrılması gerekir. İşte özel istisna türlerinin yürütüleceği yer burasıdır. Oluşturulan özel istisnalar, kütüphane kullanıcılarının karşılaşabileceği her olası soruna karşı doğru tepki vermelerine yardımcı olur.

Özet

  • Özel istisna oluştururken SystemException ve ApplicationException gibi ketegori ayrımları kullanmak yerine Exception temel sınıfından yeni istisna sınıfları üretmek daha uygundur.
  • Eğer yazdığınız kütüphaneyi sizden başka kullanacak olan yoksa, özel istisna türleri oluşturmayın. Mevcut istisna sınıflarını kullanabilirsiniz. Ya da size özel tek bir  istisna türü oluşturarak her yerde kullanabilirsiniz.
  • Eğer bir kütüphane veya framework geliştiriyorsanız ilgili kütüphaneye özel istisna türleri oluşturun. Bu sayede kütüphane geliştiricisi olarak önceden kestiremeyeceğiniz durumlara karşı kullanıcılara bir emniyet önlemi sunmuş olursunuz.

Kaynak: http://enterprisecraftsmanship.com/2016/12/08/custom-exception-types/

LINQPad Programcıların Oyun Alanı

25 Haz

LINQPad yazılımı, SqlServer, Oracle, OData servisleri gibi veri kaynakları üzerinde LINQ sorgularını kullanarak sorgular çalıştırabilen ve C#, VB, F# gibi programlama dillerini destekleyen bir editördür.

LINQPad ile desteklenen diller ve gerçekleştirilebilecek operasyonlar seçenekler halinde geliştiricilere sunulmuştur.

  • C# Expression
  • C# Statements
  • C# Program
  • VB Expression
  • VB Statements
  • VB Program
  • SQL
  • ESQL
  • F#Expression
  • F# Program

Adsız

Geliştiriciler olarak hızlı bir şekilde denemeler yapmak istediğimiz durumlar olabilir. Bu durumda hemen Visual Studio arayüzünde bir proje oluşturarak ya da mevcut bir proje üzerinde merak ettiğimiz kodları çalıştırmak durumunda kalırız. Ancak LINQPad ile hızlı bir şekilde istediğimiz sonucu hemen görebiliriz.

Örneğin C# LINQ ile rasgele şifre üretmek için hemen bir deneme yapmak istersek:

Adsız

Yazmak istediğimiz ifadeleri tamamladıktan sonra sonucu görmek için sadece .Dump() extension metodunu çalıştırmak yeterlidir.

Harici kütüphaneleri ve Nuget paketlerini referans olarak LINQPad’e eklemek ve çalıştırabilmek mümkündür.

 

C# MSMQ Mesaj Yönetimi, Okuma Yazma İşlemleri

21 Haz

MSMQ teknolojisi ile alakalı bir önceki yazıda MSMQ tanıtımını yapmış ve Windows işletim sistemlerine nasıl dahil edildiğini incelemiştik.

Bu yazıda ise mesajların MSMQ kuyruğuna nasıl yazıldığını ve kuyruktaki mesajların nasıl okunduğunu incelemeye çalışacağız.

Öncelikle mesaj nedir bundan bahsedelim. MSMQ teknolojisindeki mesaj kavramı aslında bir programlama dili ile oluşturulan nesnelerin serileştirilmiş halleridir. Bir nesne binary veya xml gibi formatlarda serileştirilebilir. Serileştirilmiş nesneler MSMQ gibi mesaj tabanlı iletişim ortamlarında mesaj olarak değerlendirilir.

MSMQ sisteminde mejsalar kuyruk denilen bir dizgede tutulur. Kuyruklar günlük hayattaki posta kutularına benzer. Postacı gelip zarfı posta kutusuna bırakır. Daha sonra ev sahibi gelip kutudaki zarfı açarak mesajı okuyarak ne yapacağını anlar ve gereğini yapar.

C# programlama dili ile MSMQ kuyruğundaki mesajları yönetmek mümkündür. Windows işletim sisteminde MSMQ kuyruğunu bilgisayar yönetimine girerek Private Queue seçeneğinden görüntüleyebiliriz.

MSMQ
MSMQ

.Net Framework içerisinde System.Messaging namespace altında mesaj trafiğini yönetebilecek tipler bulunmaktadır.

MessageQueue tipine ait üyeler yardımıyla sistemde bir kuyruk mevcut mu diye kontrol edilebilir, mevcut değilse yeni kuyruk oluşturulabilir. Mevcut kuyruğa bir mesaj eklenip, kuyruktan bir mesaj alınabilir. Aşağıdaki örnek kod ile kuyruğa mesaj yazma işlemi gerçekleştirilmektedir.

MessageQueue messageQueue = null;

if (MessageQueue.Exists(@".\Private$\EmailQueue"))
{
    messageQueue = new MessageQueue(@".\Private$\EmailQueue");
}
else
{
    // Kuyruk oluştur.
    MessageQueue.Create(@".\Private$\EmailQueue");
    messageQueue = new MessageQueue(@".\Private$\EmailQueue");
}

messageQueue.Send("Bu ilk bir MSMQ mesajıdır", "Title");

Kuyruktaki mesajları okumak senkron veya asenkron şekilde yapılabilmektedir. MessageQueue tipine ait aşağıdaki metodlar:

  • BeginPeek()
  • BeginReceive()

asenkron şekilde mesajları okumaya olanak sağlar. bu mesajların override edilmiş şekilleri burada mevcuttur.

BeginPeek() metodu çağrılmadan önce PeekComplated event handler oluşturmak gerekir ki okunan mesajın içeriğine erişebilelim. Aynı şekilde BeginReceive() metodu çağrılmadan önce ReceiveComplated event handler oluşturmak gerekir. BeginPeek() ile alınan mesajlar kuyruktan silinmezken BeginReceive() ile okunan mesajlar kuyruktan silinir. Bu fark, süreçleri yönetmek açısından önemlidir. Aşağıdaki örnek kod, tek bir mesajın kuyruktan asenkron olarak alınmasını sağlar. BeginReceive() kullanıldığı için alınan mesaj kuyruktan silinecektir.

MessageQueue messageQueue = null;

if (MessageQueue.Exists(@".\Private$\EmailQueue"))
{
    messageQueue = new MessageQueue(@".\Private$\EmailQueue");
    messageQueue.ReceiveCompleted += new
           				ReceiveCompletedEventHandler(EmailReceived);
    messageQueue.BeginReceive();
}

private static void EmailReceived (Object source,
            ReceiveCompletedEventArgs asyncResult)
{
    MessageQueue mq = (MessageQueue)source;
    Message m = mq.EndReceive(asyncResult.AsyncResult);
    Console.WriteLine("Message: " + (string)m.Body);
}

MessageQueue tipinde senkron bir şekilde mesaj almak için aşağıdaki metodları kullanılabilir:

  • Peek()
  • Receive()
  • GetAllMessages()

Yani Peek() veya Receive() metodu çağrıldığında kuyruktan bir mesaj gelene kadar başka işleme geçilmez. Oysa asenkron metodlarda BeginPeek() veya BeginReceive() komutlarından sonra başka işlem varsa onlar yürütülebilmekteydi.

GetAllMessages() metodu kuyruktaki tüm mesajları getirmek için kullanılır.

 MessageQueue queue = new MessageQueue(@".\Private$\EmailQueue");

 Message[] msgs = queue.GetAllMessages();

 foreach(Message msg in msgs)
 {
     Console.WriteLine(msg.Body);
 }

Mesaj kuyruğuna bir text yerine bir nesneyi göndermek mümkündür. Bu işlem için öncelikle serileştirilecek olan tipin belirlenmesi gerekmektedir. Serileştirilecek olan tip aşağıdaki şekliyle Email adında belirlenmiş ve [Serialize] attribute ile imzalanmıştır.

[Serialize]
public class Email{
     public string From {get; set;}
     public string To {get; set;}
     public string Body {get; set;}
}

Bu nesnenin bir örneğini kuyruğa eklemek için aşağıdaki gibi bir yöntem izlenir.

Email mail = new Email{
   From = "sender@mail.com",
   To = "receiver@mail.com";
   Body = "Merhaba bu bir test mesajıdır.";
};
MessageQueue messageQueue = null;

if (MessageQueue.Exists(@".\Private$\EmailQueue"))
{
    messageQueue = new MessageQueue(@".\Private$\EmailQueue");
}
else
{
    // Kuyruk oluştur.
    MessageQueue.Create(@".\Private$\EmailQueue");
    messageQueue = new MessageQueue(@".\Private$\EmailQueue");
}

Message message = new Message();
message.Formatter = new BinaryMessageFormatter();

messageQueue.Send(message);

Temel olarak MSMQ mesaj yönetimi bu şekilde yapılmaktadır. Buradaki örnekler yazma ve okuma işlemlerini gösteren tek bir uygulama gibi anlaşılabilir. Ancak dağıtık mimarilerde kuyruğuna yazım işlemini bir uygulama yaparken, kuyruğu sürekli kontrol etme işlemini işletim sistemine bağlı bir servis sağlıyor olabilir. Ya da zamanlanmış görev mantığı ile çalışan bir client uygulama da kuyruktaki mesajları okuyarak gerekli görevleri yerine getirebilir. Senaryoları tasarlamak tamamen ihtiyaca ve beceriye kalmıştır.

Bir sonraki yazıda görüşmek dileğiyle.

C# LINQ ile Rastgele Şifre Üretmek

4 Nis

Bu yazıda System.Linq kütüphanesinden faydalanarak rastgele şifre üretmenin ne kadar pratik ve basit olduğunu inceleyeceğiz. Bu pratik çözüme burada rastladım ve herkese faydalı olacağını tahmin ederek paylaşmak istedim.

var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
var random = new Random();
var result = new string(
    Enumerable.Repeat(chars, 8)
              .Select(s => s[random.Next(s.Length)])
              .ToArray());

Olayın gelişimini incelediğimizde Enumerable sınıfının Repeat fonksiyonundan faydalanıldığını görüyoruz.

Enumerable.Repeat fonksiyonunun syntax düzeni şu şekildedir:

public static IEnumerable<TResult> Repeat<TResult>(
   TResult element,
   int count
)

Çalışma şekli ise TResult türünde Count kadar tekrar eden bir yığın üretecek şekilde ayarlanmıştır. Örneğin 15 tane “Okul” sözcüğü üret şeklide çalışır.

Yukarıdaki şifre üretmek için oluşturulan örnekte bizim verdiğimiz bir diziden her defasında rastgele bir karakter çekildiği için tekrarlı veri yığını oluşmuyor. Sonuç olarak count değeri kadar karakter içeren bir şifre oluşturabiliyoruz.

C# Action ve Action ön tanımlı delege türü

22 Ara

Delegeler ile ilgili yazımızda delegeleri tanımlamayı ve kullanmayı incelemiştik. Delegelerin metodları temsil ettiğini ve hangi tür metodların temsil edileceğini ise delegeler oluşturulurken belirlendiğini görmüştük.

Ardından Func<T> ile ilgili yazımızda önceden tanımlanmış delege türü olan Func<T> delege türlerini incelemiştik. Func<T> ile temsil edilen metodların mutlaka bir değer döndürdüğünü belirtimştik.

Bu yazımızda ise delegelerin bir başka özel ve ön tanımlı türü olan Action ve Action<T> delege türünü incelemeye çalışacağız.

Action ve Action<T> delege türleri .Net framework 3.5 ile gelen önceden tanımlanmış bir delege türüdür. Action<T> delege türleri Func<T> delegelerinin aksine hiçbir değer döndürmeyen metodları temsil etmektedir. Action delege türü hiçbir parametre almayan ve değer döndürmeyen metodları temsil eder. Adından da anlaşılacağı üzere bir fonksiyonu değil bir eylemi(action) temsil etmektedirler.

Action<T> delegeleri birden fazla parametre alabilecek metodları da temsil edebilecek şekilde tasarlanmıştır.

Action
Action <T>
Action <T1,T2 >
Action <T1,T2,T3>
Action <T1,T2,…,TN>

Her bir T, metodların alacağı parametrelerin tiplerini belirtmektedir. Func<T> gibi Action<T> kullandığımızda delege tanımlamamıza gerek kalmamaktadır.

Action delegelerinin lambda ifadeleriyle göterimini şu şekilde yapabiliriz:

Lambda ifadelerini kullanmadan metod çağırarak action metod kullanımını şu şeklide kullanabiliriz.

Action delege tipinin kullanımına genelde LINQ ifadeleri ile çalışırken rastlarız. LINQ extension metodlarından Action delege parametre alanlara, uygun metodu parametre olarak gönderebiliriz. Buna bir örnek olarak kişilerin bulunduğu bir listedeki isimlerin önüne “Mr” ön ekini getirerek yazdırmayı deneyebiliriz.

List<T> tipinin ForEach extension metodu, string bir parametre alan metodları temsil etmektedir. Listedeki isimlere tek tek “Mr” ön ekinin nasıl getirildiğini bu şekilde görebilmekteyiz.

Bir sonraki yazıda tekrar görüşmek üzere…

C# events (olaylar) kavramı

18 Ara

Bir önceki yazımızda delegates (delegeler veya temsilciler) kavramından bahsetmiştik. Delegelerin amaçlarından birinin de event(olay) yakalyıcı metodları temsil eden tipler olduğunu vurgulamıştık.

Olaylar .Net platformunun ileri konularından biri olup ilk anda anlaşılması biraz karmasık gelebilir. Olayları anlamanın yolu da delegeleri anlamaktan geçer. Delegeler konusu anlaşılmışsa olayların (events) anlaşılması da çok basit bir hale gelecektir.

C# ortamında bir event tanımlamak şu şeklidedir:

<erişim belirleyici> event <delege tipi> <event adı>;

Public event QueryEventHandler QueryExecuted;

Public: erişim belirleyicisi. Public veya private olabilir.

QueryEventHandler: delege tipi.

QueryExecuted: event adı.

Event kullanımı .Net platformunda genellikle form tabanlı windows uygulamalarında, silverlight uygulamalarında, network uygulamalarında çok yaygındır. Örneğin bir windows forms uygulamasında bir butona tıklandığında Buton sınıfının Click adındaki event’ı için bir metod oluşturulur ve bu metod içerisine tıklama işlemi sonrası yürütülecek kodları yazabiliriz.

Biz bu yazımızda örnek olarak bir önceki c# delegeler yazımızdaki örneğin aynısını event kullanarak yapacağız. Bu sayede event ve delegate arasındaki bağıntıyı kurmak daha da kolaylaşacak.

Öncelikle bir önceki uygulamamızda ki büyük resme bakarak başlayabiliriz.

Client tarafında oluturduğumuz bir metodu Queryoperation tipinin ExecuteQuery metoduna parametre olarak göndermiştik. ExecuteQuery metodu da bizim gönderdiğimiz metod formunda bir delegeyi parametre aldığı için uygulamamız hiç sorunsuz çalışmıştı.

Bu sefer Queroperation sınıfımıza QueryExecuted adında bir event tanımlayarak bu event’a client tarafındaki bir metodu abone edeceğiz. Sorgu işlemi gerçekleştiğinde abone ettiğimiz metod çalışacaktır.

QueryOperation sınıfının artık QueryExecuted adında bir event’ı var. Bu event, void geri dönüş tipinde tipinde olan ve QueryEventArgs tipinde parametreler alan metodları yakalamakla sorumludur.

Client tarafında olayın nasıl gerçekleşeceğine bakacak olursak.

QueryOperation nesnesinin QueryExecuted event’ına client tarafında oluşturduğumuz, delegemize uygun olan onExecuted metodumuzu abone ediyoruz.

Bir metodun bir event’a abone edilmesi (+=) şeklinde yapılırken aboneliğin sona erdirilmesi ise (-=) şeklinde yapılır.

operation.QueryExecuted-=onExecuted;

şeklinde aboneliği sonlandırabiliriz. Bu sonlandırmadan sonra onExecuted metodu tetiklenmez.

Eğer event’a bir metod abone etmezsek QueryOperation sınıfının ExecuteQuery metodu içerisindeki if(QueryExecuted!=null) şartı false olarak değerlendirilir ve bizim client tarafındaki metodumuz çalıştırılmaz.

Bu yazımızda:

  • C# dilinde event kavramını
  • Event tanımlamasının nasıl yapıldığını
  • Event ve delegate arasındaki ilşkiyi
  • Event’a metod aboneliğini ve aboneliğin sonlandırılmasından
bahsettik.

Tekrar görüşmek dileğiyle…

C# delegate (Delege veya Temsilci) Kavramı

16 Ara

Bu yazımızda C# programlama dilini öğreneneler için bazen işkence haline dönüşen ve bir .Net kavramı olan delegeler üzerinde duracağız. Delegeler, adından da anlaşılacağı üzere temsilcidirler. Temsil ettikleri kavram ise metodlardır.

Delegelerin hangi tür değerleri dönrüren ve ne tür parametre alan metodları temsil ettiklerini tanımlanırken belirleriz.

Bir delegenin tanımlanış şekli aşağıdaki gibidir.

Örnek delege:

<erişim belirleyici> delegate <geri dönüş tipi> <delege adı>(<parametreler>)

 public delegate int Hesaplayici(int a,int b);

Örnek delegemizin tanımlanış biçimindeki ifadelerin ne anlama geldiklerini ise sırayla şu şeklide ifade edebiliriz.

Public: delegenin erişim belirleyicisi. Public veya private olabilir.

int: metodun geri dönüş tipi. Yani geri dönüş tipi int olan metodları temsil ediyor.

Hesaplayici: delegenin adı.

int a, int b: delegemiz, int tipinde iki adet parametre alan metodları temsil ediyor.

Yukarıda tanımlanan Hesaplayici adlı delege, int tipinde değerler döndüren ve int tipinde iki adet parametre alan metodları temsil etmektedir.

Burada aslında kafaları kurcalayan soru işareti, delegelerin bize sağladığı kolaylığın ne olacağı noktasında yatmaktadır.

Delegelerin temel olarak bize iki noktada büyük faydası vardır. Bunlar:

  • Event kullandığımız programlamada olayların yakalanacağı metodları belirlemek.
  • Çalışma zamanında (runtime) hangi tür metodların kullanılabileceğini belirlemek.

Delegelerin daha iyi anlaşılması açısında bu yazımızdaki örnek uygulamızda delegelerin çalışma zamanında (runtime), belirlediğimiz bir metodun temsil edilmesini canlandırmaya çalışacağız.

Senaryo şu şeklide olacaktır: Sql sorgularını icra etmekle sorumlu bir sınıfın metoduna, sorgu sonrasında bizim gönderdiğimiz bir görevi(metodu) yerine getirmesini sağlamaya .alışacağız. Yani bir metoda parametre olarak bir metod göndereceğiz. Sorgu sonrasında bizim gönderdiğimiz metod çalışacak.

Öncelikle query sonuçlarını yakalayan bir delege olan QueryResultHandler adında bir delege tanımlayacağız.

public delegate void QueryResultHandler(QueryEventArgs args);

Query sonuçlarını bildiren QueryEventArgs adında bir tipimiz mevcut. Bu tipte parametre alan ve void yani geriye birşey döndürmeyen metodların temsilcisini tanımlamış olduk.

public class QueryEventArgs
{
     public bool Executed { get; set; }
}

QueryEventArgs tipi aslında sadece sorgu sonucunda işlemin gerçekleşip gerçekleşmediğini argüman olarak bize veren bir tiptir.

Sql sorgu işlemlerini gerçekleştirecek olan tipimizi de QueryOperation adında bir tip olarak belirleyelim.


public class QueryOperation
{
     public void ExecuteQuery(string queryText, QueryResultHandler executed)
     {
        // execute query
        // ...
        // ..
        // .

        QueryEventArgs result =new QueryEventArgs();
        result.Executed = true;

        executed(result);
     }
}

Sınıfımız temsili bir sınıf olduğu için yani sql sorgusu gerçekleştirmiş gibi bir varsayım aptığımız bir sınıf olduğu için içeriğinde sadece ExecuteQuery adında bir metod tanımladık. Bu metod sorgu işlemini gerçekleştirip QueryEventArgs tipinde bir sonuç oluşturmakta ve parametre olarak gönderilen metodu çalışıtrmaktadır.

Şimdi client tarafında nasıl bir operasyon gerçekleştireceğimize gelelim.

static void Main(string[] args)
{
    QueryOperation operation = new QueryOperation();
    operation.ExecuteQuery("select * form Table", onExecuted);
}

public static void onExecuted(QueryEventArgs args)
{
    Console.WriteLine("query executed!");
}

Yaptığımız işlem sadece QueryOperation tipinde oluşturduğumuz bir nesneye sql sorgu parametresini ve sorgu sonrasında bizim client tarafında tanımladığımız bir metodun parametre olarak göndermektir. Bizim burada tanımladığımız onExecuted metodu tam da delegemizin (QueryResultHandler) formuna uyan bir yapıdadır.

Burada farkına varmamız gerekn bir nokta da delegelerin metod pointer(işaretçi) olduğudur. QueryOperation tipinin ExecuteQuery metodu bir temsilciyi parametre alırken, çalıştırılan bir metoddur. Yani temsilciler metodları işaret ederler.

Programı çalıştırdığımızda aşağıdaki gibi bir sonuç karşımıza çıkacaktır.

Bu örnekte:

  • delege tanımlamanın nasıl yapıldığını
  • çalışma zamanında (runtime) belirlenen bir metodun temsilcisinin çalıştırılmasını
  • delegelerinin birer metod pointer(işaretçi) olduğunu

anlamaya çalıştık.

Bir sonraki yazıda görüşmek dileğiyle…

LINQ ile String Birleştirme

17 Tem

Bazen üyelerin emaillerini çekerek toplu mail göndermek durumunda kalabiliriz. Email listesini çekmek kolaydır. Fakat bir de bu emaillerin, aralarına noktalı virgül koyarak birleştirmesi işlemi vardır. Bu işlemi iki yolla yapabiliriz.

  • Email listesini SQL ortamında noktalı virgülle ayrılmış şekilde çekmek.
  • Email listesini dizi şeklinde SQL sorguyla alıp, birleştirme işlemini kod tarafında yapmak.

Biz ikinci yöntem üzerinde duracağız.

Elimizdeki email listesi şu şekilde olsun.


List<string> data = new List<string>
{
    "aaa@mail.com",
    "bbb@mail.com",
    "ccc@mail.com",
    "ddd@mail.com",
    "eee@mail.com"
};

Bu listeyi şimdi birkaç yöntemle birleştirmeyi deneyelim.

Birinci yol: LINQ Aggregate extension metodunun kullanımı.

var emails = data.Aggregate((s, e) => string.Concat(s, ";", e));

İkinci yol: String.Join extension metodunun kullanımı.

var emails = string.Join(";", data);

Her iki yönteminde çıktısı şu şeklide olacaktır:

"aaa@mail.com;bbb@mail.com;ccc@mail.com;ddd@mail.com;eee@mail.com"

C# Linq ileKelime( Word ) Histogram Oluşturma

10 Tem

Konuya direk dalmadan önce histogramın ne olduğunu açıklamadan geçmek istemiyorum. Histogram, bir topluluktaki elemanların sayısal sıklıklarını, yoğunluklarını belirten tablolar diyebiliriz. Gösterim şekli olarak genelde grafiksel bir gösterimi vardır. İsterseniz tablo şeklinde de tutabilirsiniz. Ancak Grafiksel gösterimler daha akılda kalıcıdır.

Histogramı c# tarafında özetleyecek bir kelime analiz uygulamasının uygun olacağını düşündüm. Bu amaçla, bir döküman içerisindeki kelimelerin hangi sıklıklarla kullanıldığını çıkaran bir uygulama yapmayı planladım.

Uygulamaya başlarken öncelikle bir analiz yapan sınıf tasarlamam gerektiğine karar verdim. Analyzer adında bir sınıf oluşturarak işe başladım. Bu sınıf içerisinde de verilen text ifadenin kelimelerine ait bir histogram tablosu çıkaran GetTextHistogram adında metod oluşturdum.


public class Analyzer
{

    public IEnumerable<AnalyzeItem> GetTextHistogram(string text)
    {

       var array = text.Split(' ');
       var result = array.GroupBy(i => i.ToLower())
                         .Select(i => new AnalyzeItem { Word = i.Key, Count = i.Count() });

        return result;

    }

}

public class AnalyzeItem
{
      public string Word { get; set; }
      public int Count { get; set; }
}

Örneği incelediğimizde kelimelerin tekrarlanış miktarını veren bir tip olan AnalyzeItem tipi de göze çarpmakta. Bu tip hangi kelimenin kaç kez tekrar ettiğini bize vermekte. Örneğin  “bayram” kelimesinin kaç defa tekrar edildiğinin sonucunu tutmaktadır.

Burada LINQ nimetlerinden de faydalanmadan yapamadım. Eğer LINQ olmasaydı dizilerle kırk takla atarak sonuca ulaşmaya çalışacaktık.

Programın kullanımı da şu şeklide olacaktır.

static void Main(string[] args){

      string text = "Merhaba syn Ali Veli, size uygun şartlarda kredi imkanı ABCBANK ta. ABCBANK www.abcbank.com da. Kredi almak istiyorsanız ABCBANK a gelin.";

      Analyzer analyzer = new Analyzer();

      var data = analyzer.GetTextHistogram(text);

      foreach (var item in data)
      {
         Console.WriteLine(item.Count + "\t" + item.Word);

      }

}

Dilerseniz uygulamayı bir extension method haline de getirebilirsiniz. Onu da şu şeklide yapmak mümkündür.


public static class Extensions
{
    public static IEnumerable<AnalyzeItem> Histogram(this string text)
    {
       var array = text.Split(' ');
       var result = array.GroupBy(i => i.ToLower())
                         .Select(i => new AnalyzeItem { Word = i.Key, Count = i.Count() });

       return result;
    }

}

Bu extension metodla kodun kullanımı epeyce değişiyor.

static void Main(string[] args)
{
     string text = "Merhaba syn Ali Veli, size uygun şartlarda kredi imkanı ABCBANK ta. ABCBANK www.abcbank.com da. Kredi almak istiyorsanız ABCBANK a gelin.";

     foreach (var item in text.Histogram())
     {
           Console.WriteLine(item.Count + "\t" + item.Word);

     }
}

Artık bütün string tiplere histogram uyglamak mümkün hele geldi.

C# Kod Standatları ve En İyi Programlama Teknikleri Son– Bölüm 8

28 Kas
  1. Giriş
  2. İsimlendirme ve standartları
  3. Girintiler ve aralıklar
  4. Doğru programlama teknikleri
  5. Mimari
  6. ASP.NET
  7. Yorumlar
  8. Hata ayıklama

Hata Ayıklama

Serimizin son bölümünde hata yakalama ile ilgili bazı tekniklerden bahsedilmektedir.

  • Bir cache exception tanımlayıp içini boş bırakmak doğru bir yöntem değildir. Çünkü bir hata oluştuğunda bize bir hata mesajı dönmeyecek ve hata yokmuş gibi kod işlemeye devam edecektir. Önemsiz hatalar için bu yöntemi uygulayan geliştiriciler vardır. Fakat siz programlı olarak her zaman hataları önlemek için çalışmalısınız. Hiç değilse hataları yakalayıp log dosyasına veya veritabanına kaydedip yola devam etmelisiniz.
  • Hata oluştuğu durumlarda kullanıcıya uygun bir mesaj vermelisiniz. Fakat hatayı tüm detayları ile kayıt altına almalısınız.
  • Her zaman genel Exception’lar yerine oluşabilecek hataya özgü Exception’lar yakalayın.

İyi Kod:

Kötü Kod:

  • Tüm metodlarda hata yakalamaya gerek yoktur. Bazen uygulamanın çökmesi için açıklar bırakın. Bu sayede geliştirme aşamasında karşılaşılabiliecek hataları bulmanıza yardımcı olacaktır.
  • Try-cache bloğunu tüm metodlarda kullanmayın.  Başka bir şekilde önüne geçemeyeceğiniz hata durumları oluşacaksa kullanın. Örneğin veritabanına bir kayıt girerken kaydın zaten olup olmadığını anahtar değeriyle kontrol etmelisiniz. Bazen geliştirici kayıt sırasında kontrol etmeden giriş yapmaya çalışır ve hata durumunda kayıt zaten var zanneder. Bu kesinlikle kabul edilemez. Hata oluşmasını beklemeden önleminizi almalısınız.
  • Gerektiği durumlarda kendi hata yakalama sınıflarınızı yazın. Özel sınıflarınızı SystemException sınıfından değil ApplicationException sınıfından türetin.

Bu yazı ile birlikte kod standartları serimizin sonuna gelmiş bulunuyoruz. Umarım faydalı bir yazı dizisi olmuştur. Herkere iyi çalışmalar.