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# Conditional ve Ternary Operatorler

14 May

Yazılım geliştiriciler olarak bazen kod ekonomisine başvurmak istediğimiz durumlar olabilmektedir. Özellikle de if şartlarını oluştururken parantez açıp kapatmak yerine sınama işlemini tek satırda yapabilmekteyiz.

if(){}else{} kodu yerine kısaca ?: operatörlerinin kullanımına bakalım.

Senaryomuz, mantıksal bir durum kontrolünün sınamasına göre string değer döndürecek bir iş akışının hazırlanması şeklinde olabilir.


     bool durumu = getDurum();

     string sonuc="";

     if (durumu)
     {
        sonuc = "Onaylanmış";
     }
     else
     {
        sonuc = "Beklemede";
     }

     Console.WriteLine(sonuc);

Yukarıda basitçe, durum değişkeninin true ve false olup olmadığı kontrol edilmektedir.

Bu işlemi kısaca ?: operatörüyle yaparsak şu şekilde olacaktır.

     bool durumu = getDurum();

     string sonuc = durumu ? "Onaylanmış" : "Beklemede";

     Console.WriteLine(sonuc);

Bu şekilde if ve else yapısı iptal edilerek tek satırda işlem tamamlanmaktadır. Bir başka yazım şekli ise şu şekildedir:

     string sonuc = durumu == true ? "Onaylanmış" : "Beklemede";

Yapı şu şekildedir:

     string sonuc = <mantıksal kontrol> ? <true ise dönen değer> : <false ise dönen değer>;

Tekrar görüşmek ümidiyle…

C# Extension Metod Tanımlama ve Kullanma

11 May

Programlama dillerinde varsayılan olarak gelen tiplere yapılan eklemelere, bir başka deyişle yamalara extension metod diyebiliriz. Bu yazıda, c# ile extension methodların nasıl tanımlandığını, nasıl uygulandığını  ve hangi mantıkla çalıştığını incelemeye çalışacağız.

C# dilinin temel tipleri olan int, string, double ve sayamadığım birçok tip, object tipinden türemiştir ve object tipinin özelliklerini taşımaktadır. Biz de bu özelliklerin yanında gerekli olan metodları bu tiplere ekleyebiliriz.

Örneğin şöyle bir senaryomuz olsun: string türündeki içerikler eğer belli bir karakterden uzunsa (…) şeklinde kısaltılsın.

Bunun için extension metodumuzu hazırlayalım. Extension metodun ulaşılabilmesi için bir static class içerisinde, static bir metod olarak tanımlanması gerekir.


public static class ExtensionString
{
     public static string Kisaltma(this string text, int maxSize)
     {
          return text.Length > maxSize ? text.Substring(0, maxSize).Insert(maxSize, "...") : text;
     }
}

Yukarıda görüldüğü üzere, ExtensionString adında static bir sınıf ve Kisaltma adında static bir metod oluşturuldu. Kisaltma metodu this string şeklinde bir parametre almaktadır. Bu demek oluyor ki Kisaltma metodu, string tipindeki değişkenlere eklenecek. Yani artık her string değişkeni, Kisaltma adında bir metoda sahip.

Burada dikkat edilmesi gereken, extension metodu barındıran sınıfın kullanılmak istenen yerden görünüyor olması gerekir. Yani gerekirse using ile sınıf içerisinde tanımlanmalıdır.


class Program
{
      static void Main(string[] args)
      {
         string baslik = "Bu yazının içeriği ne kadar uzunmuş böyle.";

         Console.WriteLine(baslik.Kisaltma(10));
      }

}

Ekran çıktısı

Kisaltma metoduile 10 karakterden sonra “…” şeklinde devam edilmektedir. Artık istediğimiz yerde bu metodu kullanabiliriz.

Single SingleOrDefault ve First FirstOrDefault Farkı

11 Mar

LINQ sorgularında seçimler yaparken Single, SingleOrDefault, First ve FirstOrDefault extension metodları sık sık başvurulan metodlardır. Bu metodları kullanırken bazen beklenmeyen durumlarla karşılaşabiliriz. Bu metodlar arasındaki farkları bildiğimiz taktirde istenmeyen durumlardan da kurtulmuş oluruz.

Şimdi “Single ve SingleOrDefault arasındaki fark nedir?” ve aynı şekilde “First ve FirstOrDefault arasındaki fark nedir?” sorularının cevabını aramaya çalışalım.

Tek rakamları içeren int tipinde bir dizimiz olduğunu varsayalım. Bu diziden herhangi bir teksayıyı seçmek istediğimizde hangi durumda hangi sorguyu kullanmalıyız?

      int[] oddNumbers = { 1, 3, 5, 7, 9 };

SingleOrDefault: Eğer dizi içinden sadece bir tane sayı seçmek istiyorsak ve seçim şartımız sağlanmıyorsa, bu durumda int tipinin varsayılan değeri olan 0(sıfır) döndürülsün istiyorsak SingleOrDefault seçimini kullanmalıyız.

      int[] oddNumbers = { 1, 3, 5, 7, 9 };

      int number = oddNumbers.SingleOrDefault(n => n.Equals(4));

      Console.WriteLine(number);

Yukarda görüldüğü üzere dizi içerisinde 4 değeri olmadığı için program çıktısı 0 olacaktır.

Eğer seçim sonucunda birden fazla değer dönerse InvalidOperationException fırlatılacaktır.

      int[] oddNumbers = { 1, 3, 5, 7, 9 };

      int number = oddNumbers.SingleOrDefault(n => n > 1);

      Console.WriteLine(number);

Yukarıdaki kod parçası hata fırlatılacaktır. Çünkü 1’den büyük olan, birden fazla eleman vardır.

Single: Eğer seçimimiz sonucunda sadece bir tane eleman geleceği garanti ise, bu durumda Single seçimini kullanabiliriz. Eğer şartımızı sağlayan hiçbir eleman dönmezse veya şartımızı sağlayan birden fazla eleman dönerse, bu iki durumda da istisnalar fırlatılacak ve hata ile karşılaşmış olacağız.

      int[] oddNumbers = { 1, 3, 5, 7, 9 };

      int number = oddNumbers.Single(n => n.Equals(3));

      Console.WriteLine(number);

Yukarıdaki örnekte şartımız sağlandığı için 3 sonucu çıktı olarak gösterilecektir.


      int[] oddNumbers = { 1, 3, 5, 7, 9 };

      int number = oddNumbers.Single(n => n.Equals(2));

      Console.WriteLine(number);

Yukarıdaki örnekte ise 2’ye eşit olan herhangi bir eleman olmadığı için InvalidOperationException istisnası fırlatılacaktır.

FirstOrDefault: Bu seçimde de mantık SingleOrDefault ile aynıdır. Ancak bu seçimde istenen şartta ilk eleman seçilir. Örneğin dizinin ilk elemanı, dizinin 2’den büyük ilk elemanı gibi.

First: Mantık Single ile aynıdır, ancak seçilen ilk elemandır.

      int[] oddNumbers = { 1, 3, 5, 7, 9 };

      int number = 0;

      number = oddNumbers.FirstOrDefault(n => n > 9);  // Sonuç: 0
      number = oddNumbers.FirstOrDefault(n => n == 3); // Sonuç: 3
      number = oddNumbers.First(n => n == 5);          // Sonuç: 5
      number = oddNumbers.First(n => n > 2);           // Sonuç: 3
      number = oddNumbers.First(n => n > 9);           // Sonuç: HATA

      Console.WriteLine(number);

Umarım faydalı olmuştur. Tekrar görüşmek üzere.

C# ile Threading işlemleri

17 Oca

Threading

Threading konusu, yazılım geliştirme sürecinde çok önemli bir kavramdır. Thread’ler sayesinde birçok işi aynı anda eş zamanlı olarak yapmak mümkündür. Yürütülen iş parçacıklarını bir süre bekletmek  veya istenen anda sonlandırmakta mümkündür.

Threading işlemlerini yöneten tipler, .Net Framework tarafında System.Threading alanında barınmaktadır.

Threading konusuna başlamadan önce Thread sınıfını tanımak gerekmektedir. Bu sınıf tek bir iş parçacığı nesnesidir. Yani bir iş parçacığını başlatmayı ve süreci yönetmeyi sağlar.

Bir iş parçacığının oluşturulması şu şekilde olmaktadır.


class SingleThreading
{
  public void StartSingleOperation()
  {
    Thread thread = new Thread(new ThreadStart(work1));
    thread.Start();
  }

  private void work1()
  {
     Console.WriteLine("This is worker thread. ThreadID: {0}",
     Thread.CurrentThread.ManagedThreadId);
  }

}

Burada SingleThreading sınıfı içersinde work1 isimli işi yapan, thread nesnesidir. Yani StartSingleOperation metodu çalıştığında programdaki diğer yürütülen işlemlerin bitmesini beklemeden work1 isimli iş yapılmaya başlanır.

Multiple Thread Kullanımı

Bazı durumlarda birden fazla thread kullanarak iş süreçlerini yönetmek istediğimiz durumlar olabilir. Yani birbirini etkilemeyen, sıra beklemeden eş zamanlı olarak yapılması planlanan süreçleri için aşağıdaki örneği verebiliriz.


class MultipleThreading
{
  public void StartMultipleWriter()
  {

     Thread th1 = new Thread(new ThreadStart(WriteX));
     Thread th2 = new Thread(new ThreadStart(WriteO));

     th1.Start();
     th2.Start();
  }

  private void WriteX()
  {
    for (int i = 0; i < 300; i++)
    {
       Console.Write("X");
    }
  }

  private void WriteO()
  {
     for (int i = 0; i < 300; i++)
     {
       Console.Write("O");
     }
  }

}

Burada th1 ve th1 isimli iki nesne örneği birbirinden bağımsız olarak iki ayrı iş parçacığını yönetmektedir. Burada işlemci iş yoğunluğuna göre eşzamanlama işlemini gerçekleştirmektedir. Yani iki farklı iş bitene kadar biraz WriteX metodundan birazda WriteO metodundan yürütme işlemi yapmaktadır. Bunun ispatı olarak da şu ekran çıktısını verebiliriz.

Görüldüğü gibi bir süre X yazma işlemi yapılmış, bir süre de O yazma işlemi yapılmış. Program her çalıştığında X ve O farklı yerlerde olabilir. Çünkü işlemcinin durumuna göre hangi metodun ne kadar çalışacağı belirlenmektedir.

Önceliklerin belirlenmesi (Thread Priority)

Bazı durumlarda çoklu thread kullanırken öncelik vermek istenen iş parçacıkları olabilir. Birçok thread aynı anda start edildiğinde, bunlardan bir tanesi diğerlerine göre öncelikli olması gerekebilir. Bu gibi durumlarda imdadımıza yetişen Thread.Priority özelliğidir. Bu özellik bir enumerasyon tipindedir. Bu enum tipi, bünyesinde; Highest, AboveNormal, Normal, BelowNormal, Lovest gibi seçenekleri tutmaktadır.

Yukardaki örnekte iş parçacıkları başlatılmadan önce öncelikleri şu kelikde belirleyelim.

public void StartMultipleWriter()
{
   Thread th1 = new Thread(new ThreadStart(WriteX));
   Thread th2 = new Thread(new ThreadStart(WriteO));

   th1.Priority = ThreadPriority.Lowest;
   th2.Priority = ThreadPriority.Highest;

   th1.Start();
   th2.Start();

}

Yani WriteX metodu WriteO metodundan daha az öncelikli olsun. Bu durumda işlemci, WriteO metodunun işlemini daha önce bitirecektir.

Ekran çıktısından da anlaşılacağı gibi WriteX metodu daha az öncelikli olduğundan X yazma işlemi sonlara bırakılmıştır.

Thread.Join metodu ile iş parçacığının bitmesini beklemek

Thread.Join() metodu bir iş parçacığının başka bir göreve başlamadan önce tamamlanması için bekletir. Ayrıca metodun overload edilmiş bir hali ile, belirlenen bir süre kadar işlemin yapılması sağlanır. Belirlenen süre içinde işlem biterse metod geriye True değer döndürür, aksi halde False döndürür.

Örneğin “Thread1” ve “Thread2” adında iki iş parçacığını sırayla çalıştırdığımızı varsayalım. “Thread1” çalışırken ”Thread2.Join()” metodunu çağırdığımızda “Thread2” işlemini bitirene kadar “Thread1” bekler. Ardından “Thread1” işlemine devam eder. Eğer ”Thread2.Join(int)” metodu çağırıldğında ise, belirlenen süre içinde işlem bitmezsse bekleyen diğer iş parçacığı çalışmaya başlar.

Bu yazımızda threading işlemlerinden  bahsetmiş olduk. Umarım faydalı bir yazı olmuştur.

C# ile XML Serileştirme (serialization)

28 Ara

XML yapısı metin tabanlı bir standarttır. HTML yapısına çok benzer biçimde oluşturulmuştur ve notepad ile bile okunabilir bir dokümandır. XML sayesinde artık dökümanlar(Microsoft Office dökümanları), resim, müzik, binary dosyalar ve veritabanı bilgileri saklanabilmektedir.

.Net Framework’te xml dostalarının okunması ve yazılması işlemlerini barındıran kütüphaneler System.Xml.Serialization ad uzayındadır.

XML Serileştirmenin Avantajları

XML yapısının en büyük avantajlarından biri platform bağımsızlığıdır. Yani herhangi bir işletim sisteminde veya herhangi bir uygulamada oluşturulmuş bir XML döküman .Net tarafından rahatça kullanılabilir. Diğer avantajları şu şekilde sıralayabiliriz.

  • XML metin tabanlı bir satandart olduğundan tüm platformlar XML işlemlerini gerçekleştirebilen kütüphaneler bulunur. Bu sayede platform uyumluluğu vardır.
  • XML yapıda serileştirilen nesneler, Notepad gibi metin editörleri tarafından görüntülenebilmektedir.

XML yapıdaki serileştirmelerde  birçok kolaylık sağlanmış olsada aşağıdaki gibi bazı sınırlamalar da vardır.

  • XML serileştirmede sadece public veriler serileştirilir. Private veriler serilştirilmez.
  • Grafiksel objeler serileştirilemez, sadece nesneler serileştirilir.

Örnek:


    FileStream stream = new FileStream(fileName, FileMode.OpenOrCreate);
    XmlSerializer serializer = new XmlSerializer(typeof(DateTime));
    serializer.Serialize(stream, System.DateTime.Now);

Örnek:


    FileStream stream = new FileStream(fileName, FileMode.Open);
    XmlSerializer serializer = new XmlSerializer(typeof(DateTime));
    DateTime date = (DateTime)serializer.Deserialize(stream);

XML ile serileştirilebilen sınıflar oluşturmak

XML ile serileştirilecek bir sınıf oluşturulurken şu kurallara dikkat etmek gerekmektedir.

  • Sınıf erişimi public olarak belirlenmelidir.
  • Serileştirilmek istenen tüm sınıf üyeleri public olmalıdır.
  • Parametresiz kurucu metodlar(constructors) oluşturulmalıdır.

Standart serileştirmedeki gibi sınıfın [Serializable] ile imzalanmasına gerek yoktur.


[XmlRoot("CartItems")]
public class CartItems
{
   [XmlAttribute]
   public int Id { get; set; }
   public string Name { get; set; }
   public decimal Price { get; set; }
   public int Quantity { get; set; }
   [XmlIgnore]
   public decimal Total { get { return Price * Quantity; } }
}

Yukardaki sınıfa ait bir nesnenin XML olarak serileştirildiğinde oluşacak XML içeriği aşağıdaki gibidir.


<?xml version="1.0"?>
 <CartItems Id="2" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
                   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <Name>Book</Name>
    <Price>5.96</Price>
    <Quantity>2</Quantity>
 </CartItems>

Dataset nesnelerini XML olarak serileştirme

Public erişimli bir sınıfa ait nesnelerinin serileştirildiği gibi DataSet nesnelerini de serilştirmek mümkündür.

    DataSet dataSet = new DataSet("MyDataset");
    DataTable dataTable = new DataTable("Users");
    DataColumn dataColumn = new DataColumn("FirstName");
    DataColumn dataColumn2 = new DataColumn("LastName");

    dataSet.Tables.Add(dataTable);
    dataTable.Columns.Add(dataColumn);
    dataTable.Columns.Add(dataColumn2);

    for (int i = 0; i < 10; i++)
    {
       DataRow row = dataTable.NewRow();
       row[dataColumn] = "User" + i;
       row[dataColumn2] = "Last Name" + i * 2;
       dataTable.Rows.Add(row);
    }

    FileStream stream = new FileStream("Dataset.xml", FileMode.OpenOrCreate);
    XmlSerializer seri = new XmlSerializer(typeof(DataSet));

    seri.Serialize(stream, dataSet);
    stream.Close();

Örnekte görüldüğü gibi sadece dataset nesnesi oluşturularak XmlSerializer yardımıyla serileştirme işlemi kolayca yapılabilmektedir.

Umarım faydalı bir yazı olmuştur. Herkese iyi çalışmalar.

C# ile serileştirme (serialization)

24 Ara

Veri merkezli uygulamalarda verileri saklamak veya transfer etmek gibi durumlarla sık sık karşılaşırız. Verilerin bir kaynaktan alınması veya bir yere depolanması nesneler aracılığı ile gerçekleştirilir. Ancak her programlama dilinde farklı yani platformda kendine özgü bir nesne yapısı olduğundan dolayı, bir platformun diğerinin nesne yapısını bilmesi beklenemez. Bu gibi durumlarda verilerin platform bağımsız bir şeklide depolanması veya transfer edilmesi amacıyla bazı standartlar oluşturulmuştur. Bu standartlardan bazıları Binary, Simple Object Access Protocol(SOAP), JSON veya XML şeklinde belirlenmiştir.

Serileştirme nedir?

Bir nesnedeki verinin bir yerde depolaması veya ağ ortamında bir yerden bir yere gönderilmesi gerektiği durumlarda uygun formata dönüştürülmesi işlemine serileştirme denir. Serileştirilen nesneler veritabanı, hafıza veya dosya gibi ortamlarda saklanabilirler.

serialization

 

 

 

 

 

Deserialization ise bu işlemin tam tersidir.

.Net Framework ile serileştirme

Serileştirme işlemini ve serileştirilmiş nesneleri dönüştürme işlemini gerçekleştirecek olan nesneler, System.Net.Runtime.Serialization ad uzayında bulunmaktadır. Serialization işlemi, bir nesneyi, depolamak veya serileştirmek amacıyla istenen formata dönüştürme işlemidir. Deserialization ise serileştirilmiş biçimdeki verilerin tekrar nesnelere dönüştürülmesi işlemidir. Örneğin, network ortamında bir bilgisayardan başka bir bilgisayara veri transferi gerçekleştirmek için önce bağlantı kurulur, ardından gönderilecek olan nesne oluşturduğumuz uygulama tarafından serileştirilir, daha sonra uzak bilgisayardaki uygulama tarafından deserialization işlemi ile aktarılan veri anlamlı bir nesneye dönüştürülür.

  1. Binary Serialization
  2. SOAP Serialization
  3. JSON Serialization

1-Binary Serialization / Deserialization (İkili Serileştirme)

Binary serişeltirme işlemi için gerekli olan sınıflar  System.Runtime.Serialization.Formatters.Binary altında bulunurlar.

  • Binary serialization işleminde nesneler byte array şekline dönüştürülür.
  • Binary deserialization işleminde byte array şeklindeki tekrar nesneye dönüştürülür.
 public static byte[] BinarySerialize(object graph)
 {
     using (var stream = new MemoryStream())
     {
         var formatter = new BinaryFormatter();
 
         formatter.Serialize(stream, graph);

         return stream.ToArray();
     }
 }

 public static object BinaryDeserialize(byte[] buffer)
 {
     using (var stream = new MemoryStream(buffer))
     {
        var formatter = new BinaryFormatter();

        return formatter.Deserialize(stream);
     }
 }

Burada binary serialization işlemini gerçekleştiren BinaryFormatter sınıfıdır. BinaryFormatter sınıfı parametre olarak bir Stream nesnesi aldığı için MemoryStream kullanılmıştır.

Örnek: Serileştirme işlemi sırasında kullanılacak olan veri tipimiz PlaceOrder isminde bir sınıf olsun.


 [Serializable]
 public class PlaceOrder
 {
     public Guid Id { get; set; }
 }

Bu sınıfa ait bir verinin serileştirme işlemi şu şekilde gerçekleştirilir.


 public class Program
 {
     static void main(string[] args)
     {
         PlaceOrder order = new PlaceOrder();
         var seralized = BinarySerialize(order);
         var deserialized = BinaryDeserialize(serialized);
     }
 }

Not: Yukarıdaki örnekte PlaceOrder sınıfı [Serializable] attribute ile işaretlenmiş ve serileştirilebilir hale getirilmiştir. Bu işaretleme BinaryFormatter kullanarak yapılan serileştirme işlemlerinde zorunludur. Aksi taktirde runtime esnasında SerializationException hatası oluşacaktır.

serializationexception

Serileştirilebilir sınıflar nasıl oluşturulur?

Bir sınıfa ait nesneleri serileştirilebilir hale getirmek için sınıfa ait nesnelerin [Serializable] ile imzalanması gerekmektedir. Serileştirme işlemini gerçekleştirdiğinizde runtime esnasında private erişimli üyeler dahil tüm sınıf üyeleri serileştirilir.

Örnek:

    [Serializable]
    public class PlaceOrder
    {
        public Guid Id { get; set; }
        public string Name { get; set; }
    }

Sınıf içersinde bir üyeyi serileştirmeden hariç tutmak için o üyenin [NonSerialized] ile imzalanması gerekmektedir.

Örnek:

    [Serializable]
    public class PlaceOrder
    {
        public Guid Id { get; set; }
        [NonSerialized]
        public string Name { get; set; }
    }

Bu şekilde Name üyesi serileştirme işlemine dahil edilmeyecektir.
Serileştirilmemiş nesneler ile deserialization işlemi sonrası işlem yapmak için IDeserializationCallback.OnDeserialization metodunu çağırarak, bu metod içerisinde istenen işlemleri gerçekleştirebiliriz.

Örnek:

    [Serializable]
    public class ShoppingCartItem: IDeserializationCallback
    {
       public string Name { get; set; }
       public int Quantity { get; set; }
       public decimal ListPrice { get; set; }
       [NonSerialized]
       public decimal Total;

       #region IDeserializationCallback Members
        public void OnDeserialization(object sender)
        {
           Total=Quantity*ListPrice;
        }
       #endregion
    }

2-SOAP Serialization / Deserialization (SOAP Serileştirme)

Bir nesnenin Simple Object Access Protocol(SOAP) protokolü üzerinden transfer edilebilmesi için bu protokole uygun bir şekilde serileştirilmesi ve serileştirilen nesnenin tekrar nesneye dönüştürülmesi işlemleridir. SOAP serileştirme işlemleri için gerekli sınıflar System.Runtime.Serialization.Formatters.Soap altında bulunurlar.

 
   public static string SoapSerialize(object graph)
  {
     using (var stream = new MemoryStream())
     {
        var formatter = new SoapFormatter();

        formatter.Serialize(stream, graph);
 
        return Encoding.UTF8.GetString(
                  stream.GetBuffer(), 0, (int)stream.Position);
     }
  }

  public static object SoapDeserialize(string buffer)
  {
     using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(buffer)))
     {
         var formatter = new SoapFormatter();

         return formatter.Deserialize(stream);
     }
  }

Örnek: SOAP serileştirilmiş bir nesnenin görünümü:


 public class Program
 {
     static void main(string[] args)
     {
         PlaceOrder order = new PlaceOrder
         {
             Id = Guid.NewGuid()
         };
         var soapseralized = SoapSerialize(order);
         var soapdeserialized = SoapDeserialize(soapserialized);
     }
 }

soap serialization

3- JSON Serialization

Nesneleri JSON şeklinde serileştirme işlemi için Json.Net kütüphanesi kullanılabilir. Bu kütüphane nuget paketi olarak bu adresten indirilebilir.

 
  public static string JsonSerialize(object graph)
  {
      return JsonConvert.SerializeObject(graph);
  }

  public static object JsonDeserialize(string seralized)
  {
      return JsonConvert.DeserializeObject(seralized);
  }

Örnek JSON serileştirilmiş nesne.
json

Not: Json serileştirme sonucunda .Net ile ilgili bilgiler Json nesnesine eklenmez. Örneğin nesnenin hangi namespace ve hangi sınıfa ait olduğu bilgisi yoktur. Bu bilgilerinde eklenmesini istiyorsanız JsonSerializerSettings sınıfını serileştirme ve deserileştirme işlemi sırasında kullanmalısınız. JsonSerializerSettings sınıfının TypeNameHandling üyesi TypeNameHandling.Objects şeklinde düzenlenmelidir.

 
 public static string JsonSerialize(object graph)
 {
     return JsonConvert.SerializeObject(graph, 
         Formatting.None, 
         new JsonSerializerSettings
         {
            TypeNameHandling = TypeNameHandling.Objects
         });
 }

 public static object JsonDeserialize(string seralized)
 {
     return JsonConvert.DeserializeObject(seralized, 
         new JsonSerializerSettings
         {
            TypeNameHandling = TypeNameHandling.Objects
         });
 }

json

[Serializable] Attribute Kullanmadan Binary Serileştirme

BinaryFormatter veya SoapFormatter kullanarak serileştirme işlemleri gerçekleştirilen sınıfların [Serializable] attribute ile imzalanması gerektiğini söylemiştik. Ancak Json serileştirme yaparken sınıfların [Serializable] attribute ile imzalanmasına gerek yoktur.


 public class PlaceOrder
 {
     public Guid Id { get; set; }
 }

PlaceOrder sınıfına ait nesneler JsonConvert ile [Serializable] attribute olmadan serileştirilebilir.

Bu durumda eğer BinaryFormatter veya SoapFormatter gibi serileştirme işlemlerinden önce JsonConvert ile serileştirme yapılıp ardından binary serileştirme yapıldığında sınıfların [Serializable] attribute ile imzalanmasına gerek kalmaz.

Örnek:


 public static byte[] BinarySerializeWitoutSerializable(object graph)
 {
   using (var stream = new MemoryStream())
   {
      var formatter = new BinaryFormatter();

      formatter.Serialize(stream, JsonConvert.SerializeObject(graph));

      return stream.ToArray();
   }
 }

Ancak bu durumda art arda iki defa serileştirme işlemi gerçekleştirilmiş olur.

.Net Framework Dosya Sistemine Genel Bakış

19 Ara

Dosya, klasör ve sürücü işlemleriyle ilgili sınıflar System.IO ad uzayında bulunmaktadır. Dosya sistemi ile ilgili snıflar bilgilendirme ve hizmet amaçlı olarak iki grupta incelenmektedir.

ilgi amaçlı sınıfların çoğu FileSystemInfo sınıfından türetilmiştir. Bu sınıflar dosya sistemi nesneleri (dosya, klasör ve sürücüler) hakkında bütün bilgileri vermektedir. Bilgi sınıfları FileInfo ve DirectoryInfo adında iki sınıftır.

Ayrıca DriveInfo sınıfı da sistemdeki bir sürücüyü temsil etmektedir. Ancak bir bilgilendirme sınıfıdır. FileSystemInfo sınıfından türetilmediği için de sürücü silme gibi bazı davranışları göstermez.

Hizmet amaçlı sınıflar dosya, dizin ve dosya yolları üzerinde bazı işlemleri gerçekleştirmek için bazı statik metodlar sunarlar. Hizmet sınıfları File, Directory ve Path sınıflarıdır.

FileSystemInfo Sınıfı

Bu sınıf dosya sistemindeki bilgilendirme sınıflarına temel oluşturur. FileSystemInfo sınıfının özellikleri ve metodları aşağıdaki gibidir.

Özellikler: Attribures, CreationDate, Exist, Extension, FullName, LastAccessTime, LastWriteTime, Name

Metodlar: Delete, Refresh

FileInfo Sınıfı

Dosya sistemindeki tek bir dosyaya erişmek için gerekli işlevselliği sağlar.

Özellikler: Dictionary, DirectoryName, IsReadOnly, Length

Metodlar: AppendText, CopyTo, Create, CreateText, Decrypt, Encrypt, MoveTo, Open, OpenRead, OpenText, OpenWrite, Replace

Örnek 1: Dosya bilgisine erişmek.

FileInfo file = new FileInfo(@"c:\test.txt");

if (file.Exists)
{
   Console.WriteLine("File Name: {0}      ", file.Name);
   Console.WriteLine("File Path: {0}      ", file.FullName);
   Console.WriteLine("File Size: {0} bytes", file.Length);
}

Örnek 2: C sürücüsündeki bir dosyayı uygulamanın çalıştığı debug dizinine kopyalamak.

FileInfo file = new FileInfo(@"c:\test.txt");
file.CopyTo("copyOfText.txt");

 

Örnek 3: Klasördeki dosyalara erişmek

DirectoryInfo info = new DirectoryInfo(@"c:\windows");

foreach (FileInfo item in info.GetFiles())
{
   Console.WriteLine("File Name: {0}", item.Name);
}

DriveInfo Sınıfı

DriveInfo sınıfı, dosya sistemindeki bir sürücünün bilgilerine ukaşmayı sağlar.

Özellikler: AvailableFreeSpace, DriveFormat, DriveType, IsReady, Name, RootDirectory, TotalFreeSpace, TotalSize, VolumeLabel

Metodlar: GetDrives(Sistemdeki bütün sürücüleri verir)

DriveType Enumerasyonu

Sürücünün olabileceği tipleri tutan bir temsili numaralandırmadır.

CDRom, Fixed, Network, NoRootDirectory, Ram, Removable, Unknown

Örnek:


DriveInfo[] drives = DriveInfo.GetDrives();

foreach (var item in drives)
{
    Console.WriteLine("Drive Name: {0}", item.Name);
    Console.WriteLine("Drive Type: {0}", item.DriveType);
}

Path Sınıfı

Path sınıfı dosya sistemindeki dosya yollarına erişmeyi ve gerekli işlemleri yapmayı sağlar.

Metodlar: ChangeExtension, Combine, GetDirectoryName, GetExtension, GetFileName, GetFileNameWithoutExtension, GetFullPath, GetPathRoot, GetRandomFilneName, GetTempFileName, GetTempPath, HasExtension, IsPathRooted

Örnek:

string targePath = @"c:\text.txt";

Console.WriteLine("Path       {0}", targePath);
Console.WriteLine("Extension: {0}", Path.GetExtension(targePath));

Console.WriteLine("Changed Extension as {0}", Path.ChangeExtension(targePath, "bak"));

 

FileSystemWatcher sınıfı

Bu sınıf dosya sisteminde istenen dizini dinlemeye yarar.  Yani dizinde bir dosya veya klasör olşturulduğunda, silindiğinde ya da değiştirildiğinde  bu olayları yakalamak mümkündür.

Özellikler: EnableRaisingEvents, Filter, IncludeSubdirectories, NotifyFilter, Path

Metodlar: WaitingForChanged

Olaylar: Changed, created, Deleted, Renamed

Örnek:


FileSystemWatcher watcher = new FileSystemWatcher(@"d:\");

watcher.EnableRaisingEvents = true;

watcher.Created += new FileSystemEventHandler(watcher_Changed);

watcher.Deleted += new FileSystemEventHandler(watcher_Changed);

Console.ReadLine();

Olay gerçekleştiğinde  çalışacak metod ise şu şekilde olmalıdır.


static void watcher_Changed(object sender,FileSystemEventArgs e)
{
     Console.WriteLine("Directory changed({0}): {1}", e.ChangeType, e.FullPath);
}

Umarım faydalı bir yazı olmuştur.

Kısaca Generic(Türe Özgü) Sınıflar

11 Ara

Generic tipler .Net 2.0 ile birlikte gelen yeniliklerden birisidir. Generic tipte yapılan bir tanımlama, bu tipin hangi tipler ile çalışabileceğini belirlemeye olanak sağlamaktadır. .Net platformunda generic tiplere örnek olarak List<T>, Nullable<T>, Dictionary<T,K> gibi tipleri verebiliriz. Bu tipler System.Collections.Generic ad uzayında barınmaktadır. Bunun yanında kendi generic  tiplerimizi tanımlamak da mümkündür.

Neden Generic Tipleri Kullanmalıyız
Generic tipleri kullanmamızın en temel sebeplerinden biri, nesnelerin Object türüne dönüştürülmesi(casting işlemi) veya Object türündeki nesnelerin istenen tipe çevrilmesi sorunudur. Yani generic kullanımlar sayesinde tip dönüştürme sorununu ortadan kaldırmaktır. Generic tiplerin iki önemli avantajı bulunmaktadır.

  • Runtime(Çalışma zamanı) Hataları: Object tip dönüşütürme işlemi sırasında oluşabilecek hataları derleyici anlayamamaktadır. Örneğin string tipindeki bir değişkeni object tipine dönüştürdüğümüzü varsayalım, daha sonra da bu object türünü int tipine dönüştürmeye çalıştığımızda derleme sırasında bir hata oluşmayacaktır. Ancak runtime esnasında bir hata oluşacaktır. Generic tiplerin kullanılması ise bu hataların derleme sırasında yakalanarak müdahale edilmesini sağlamaktadır. Ayrıca oluşturulan generic tiplerin hangi tipler ile çalışabileceğini de sınırlayabilmekteyiz.
  • Performans etkisi: Tip dönüştürme işlemleri işlemcinin zamanını almakta ve performansı olumsuz etkilemektedir. Generic tiplerde ise böyle bir durum söz konusu değildir. Çalışılacak türler başlangıçta belirlendiği için tip dönüşümüne gerek kalmamaktadır.

Örnek:


class ObjectTest
{

   public object T;
   public object K;

   public ObjectTest(object t, object k)
   {
      T = t;
      K = k;
   }
}

class GenericTest<T,K>
{
   public T t;
   public K k;

   public GenericTest(T t, K k)
   {
      this.t = t;
      this.k = k;
   }
}

Yukardaki örnekte ObjectTest sınıfı tip dönüşümlerini gerektirecek bir türü temsil etmekte, GenericTest sınıfı ise kullanılacak tip dönüşümüne gerek duymuyor. Bunu şu şekilde ispatlayabilirsiz.

static void Main(string[] args)
{
   ObjectTest obTest = new ObjectTest("Merhaba ", "dünya");
   Console.WriteLine((string)obTest.T + (string)obTest.K);

   GenericTest<string, string> genTest =
                  new GenericTest<string, string>("Merhaba ", "dünya");
   Console.WriteLine(genTest.t+ genTest.k);
 }

Yukarıda sınıfların kullanımı sırasında generic tip örneği başlangıçta iki adet string tipi ile çalışacağını belirlemeye izin veriyor. Bu yüzden tip dönüşümüne gerek kalmıyor.

Umarım faydalı bir yazı olmuştur.

Bu yazıyla ilgili çalışan bir uygulamanın kodlarını buradan bulabilirsiniz.

Referans Tipleri (Reference Types)

10 Ara

Referans tipleri .Net Framework platformunda çok kullanılan tiplerdir. Referans tipleri büyük bir  esnekliğe sahip olmakla beraber metodlarda kullanılırken çok iyi performas sağlar.

Referans tipleri stack bölgesinde dataların bulunduğu adresleri depolarlar. Pointer olarakta adlandırılabilir. Adreslerin işaret ettiği asıl veriler ise belleğin heap adı verilen bölgesinde depolanmaktadır. Çalışma zamanı (Runtime) garbage collection diye bilinen bir mekanizma sayesinde bellek yönetimini kontrol etmektedir. Garbage collection ise çöp toplayıcı bir mekanizmadır. Yani belleği periyodik olarak kontrol eder ve bellekte artık kullanılmayan öğeri yok eder.

Referans ve Değer Tiplerinin Karşılaştırılması

Bir referans tipi adres bilgisi barındırdığı için bir referans tipi değişkenini başka bir referans tip değişkenine atadığımızda değişkenin sadece adresi kopyalanmış olur. Yani veriler kopyalanmaz. Sadece iki değişkende aynı heap bölgesini işaret etmektedir.

Örnerk:

Struct Selection
 {
      public int val;
      public Selection(int Val)
      {
        val=Val;
      }

      public override string ToString()
      {
         return val.ToString();
      }
 }

Selection adında bir structure hazırladık ve aşağıdaki gibi iki Selection tipini kopyalamaya çalışalım.


 Selection s1 = new Selection(0);
 Selection s2= s1;
 s1.val+=1;
 s2.val+=2;
 Console.WriteLine("s1 = {0},s2 = {1}", s1, s2);

Bu örnekte çıktı olarak “s1=1, s2=2” sonucunu alırız. Bunun sebebi struct tipinin bir değer tipi olmasıdır. Eğer Selection yapısının tipini class olarak değiştirirsek çıktı olarak “s1=3, s2=3” sonucunu alırız. Yani Selection tipini değiştirmekle değer tipinden referans tipine geçirmiş oluruz.

Built-in Referans Tipleri

.Net Framework bünyesinde 2500 den fazla mevcut (built-in) referans tipi barınmaktadır. Bunlardan en çok kullanılanlar aşağıdaki tabloda verilmektedir.

Type Kullanım
System.Object Framework’ün en genel tipidir. Bütün tiplerde bulunan ToString, GetType, Equals gibi metodları  bünyesinde barındırır.
System.String Text şeklindeki verileri tutar.
System.Text.StringBuilder Dinamik text verilerini tutar.
System.Array Dizileri temsil eder.
System.IO.Stream Dosya, aygıt ve network ortamında kullanılır.
System.Exception Sistem ve uygulama bazındaki istisnaları yakalar.

String ve StringBuilder sınıfları

Bu sınıflar test verilerini tuttukları gibi tuttukları veriler üzerinde işlem yapabilme yeteneğine de sahiptir.

Örneğin System.String sınıfı bünyesinde birçok üye bulundurmaktadır.


string s = "this is some text to search";

s = s.Replace("search", "replace");

Console.WriteLine(s);

System.String sınıfının bir başka özelliği ise değiştirilemez olmasıdır. İyi ama bu ne demek? Bu şu anlama geliyor; çalışma zamanında(runtime) esnasında string tipinede bir değişkende herhangi bir değişiklik yapmak demek eski string yerine yeni bir string oluşturmak demektir.

Örnerk:


string s;
s = "wombat";       // "wombat"
s += " kangaroo";  // "wombat kangaroo"
s += " wallaby";     // "wombat kangaroo wallaby"
s += " koala";         // "wombat kangaroo wallaby koala"

Console.WriteLine(s);

Yukardaki örnekte saadece son stringin referansı bulunmaktadır. Yani önceki üç veri çöptoplama esnasında yok edilecektir. Bu tür geçici işlemlerden uzak durmak performans açısından önemlidir. Bu durumdan kaçınmak için birkaç yol vardır.

  • String sınıfının Contact, Join veya Format metodlarını kullanarak bir string ifadesine birden çok öğeyi eklemek mümkündür.
  • StringBuilder sınıfını kullanarakdinamik olarak string oluşturmak mümkündür.

StringBuilder sınıfını kullanmak en esnek yöntemdir. Çünkü birden fazla  ifadeyi birleştirebilen bir yapıya sahiptir. Varsayılan kurucu metodu 16 bayt uzunluğunda bir tampona sahiptir. İhtiyaç oldukça genişleyebilmektedir. İsenilen büyüklükte başlangıç boyutu ve maksimum boyutu belirlenebilmektedir.

Örnek:


System.Text.StringBuilder sb = new System.Text.StringBuilder(30);
sb.Append("wombat");  // string oluştur.
sb.Append(" kangaroo");
sb.Append(" wallaby");
sb.Append(" koala");
string s = sb.ToString();    // onucu bir string değişkenine aktar.

Console.WriteLine(s);

String sınıfının diğer bir önemli özelliği ise System.Object operatörlerinin aşırı yüklenmesidir. Aşağıdaki tabloda string sınıfının aşırı yüklenmiş operatörleri verilmektedir.

Operatör C# İşlevi
Ekleme + İki string değişkenini birleştirir.
Eşitlik == İki string değişkenin aynı ieriğe eşit olup olmadığını kontrol eder.
Eşitsizlik != Eşitsizliği kontrol eder.
Atama = String ifasesini diğer bir string ifadesine kopyalar.

Diziler

Diziler C# dilinde köşeli parantezler ile ifade edilmektedir. String tipinde olduğu gibi System.Array sınıfının da kendine özgü üyeleri bulunmaktadır. Bu üyeler dizi içindeki verilerle çalışmaya yarar. Örneğin bir dizinin verilerinin sıralanması için şu metodu kullanabiliriz:

Array.Sort(array);

Diziyi tanımlamak ve dizinin verilerine ulaşmak ise şu şekildedir.


int[] array = { 5, 81, 2, 62 };

Array.Sort(array);

Console.WriteLine("{0}, {1}, {2}", array[0], array[1], array[2]);

Streams

Stream tipleri disk üzerine veri yazıp okuk veya ağ üzerinden iletişim sağlamak için kullanılır. System.IO.Stream tipi tüm stream tipler için temel oluşturur. Aşağıdaki tabloda en çok kullanılan stream tipler listelenmektedir. Ağ akışları için kullanılan stream tipler System.Network.Sockets ad uzayında bulunmaktadır.

System.IO Tipleri Kullanımları
FileStream Dosya okuma ve yazma işlemleri.
MemoryStream Bellek okuma yazma işlemleri.
StreamReader Akışkan ortam verilerini okumak için kullanılır.
StreamWriter Akışkan ortamlara veri yazmak için kullanılır.

En basit tipler olan StreamReader ve StreamWriter text dosyası oluşturmamızı sağlar. Varsayılan kurucu metoda dosya adını girerek tek satırda dosyaya erişmek mümkündür. Dosya ile işlem bittiğinde Close metodu çağrılarak dosya kilidi kaldırılmalıdır. Aşağıda dosya yazma ve okuma işlemine bir örnek verilmektedir.


StreamWriter sw = new StreamWriter("text.txt");
sw.WriteLine("Hello, World!");
sw.Close();

 StreamReader sr = new StreamReader("text.txt");
Console.WriteLine(sr.ReadToEnd());
sr.Close();

İstisnalar (Exception)

Bir uygulamanın beklenmedik durumlarda normal çalışmasını kesmek için kullanılır. Örneğin, taşınabilir bir disk üzerindeki çok fazla veri içeren bir dosyadan okuma işlemi gerçekleştirirken diskin çıkarıldığında uygulama okuma işlemine devam edemeyecektir.

İstisnalar(Exceptions) bu gibi durumlarda uygulamanın tamamen sonlamasını engellemek, oluşan hatanın yakalanmasın sağlamak için kullanılır. Aşağıda buna uygun bir örnek verilmektedir.

try
 {
    StreamReader sr = new StreamReader(@"C:\test.text");
    Console.WriteLine(sr.ReadToEnd());
 }
 catch (Exception ex)
 {
   Console.WriteLine("Error reading file: " + ex.Message);
 }

Yukardaki örnekte bir hata oluşması durumunda, oluşan hata catch bloğu tarafından yakalanacaktır. Eğer bir hata oluşmazssa cacth bloğu atlanacaktır.

Temel sınıf olan Exception sınıfının yanında .Net platformunda, System.SystemException sınıfından türemiş yüzlerce istisna sınıfı bulunmaktadır. Ayrıca System.ApplicationException sınıfından türeterek kendi istisna sınıflarımızı da oluşturabilirz.

Birden fazla istisnanın olduğu durumlarda hataların farklı türlerine göre farklı yanıt verilir. Bu durumda birden fazla cache bloğu hataları en özelden en genele doğru sıralayarak oluşrurulur.

Hata yakalama mekanizması try ve catch bloğu yanında bride finally bloğu vardır. Finally bloğu try ve catch bloklarından sonra çalışır. Bunu şöyle bir örnekle açıklayabiliriz. Örneğin bir dosyayı okumak StreamReader için açtınız ve dosya kilitlendi. Okuma işlemi bitip Close metodu çalışana kadar dosya açık kalacaktır. Bu gibi durumlarda finally bloğunda Close metodu çağrılabilir.

StreamReader sr = new StreamReader("text.txt");

try
{
  Console.WriteLine(sr.ReadToEnd());
}
catch (Exception ex)
{
  Console.WriteLine("Error reading file: " + ex.Message);
}
finally
{
  sr.Close();
}

Yukarıdaki Finally bloğundan Try bloğu içindeki değişkenlere erişilemediği için StreamReader nesnesi Try bloğu dışına tanımlanmıştır.

Genelde basit değişken tanımlamaları dığında herşey try bloğu içinde olmalıdır. Hata yakalama işlemi sayesinde uygulamalar daha kullanışlı hale getirilebilmektedir. Ancak bu işlemin performansa olumsuz yönde etkisi olmaktadır.

Bu yazıyla ilgili çalışan bir uygulamanın kodlarını buradan bulabilirsiniz.

Kaynak: MCTS Self-Paced Training Kit: Microsoft .Net Framework 2.0 Application Development Faundation