Operatörlerin Aşırı Yüklenmesi (Operator Overloading C#)

27 May

Bu yazımızın konusu geliştiriciler tarafından oluşturulan sınıflar veya yapılar(struct) üzerinde operatörlerin aşırı yüklenmesidir. Operatörlerin aşırı yüklenmesi, bir operatörün bir nesne için bizim istediğimiz şekliyle çalışabilecek hale getirilmesidir diyebiliriz. Örneğin bir (+) operatörü varsayılan olarak iki sayının toplamı bulmak için veya iki ayrı metnin birleştirilmesi için kullanılır. Bazen yazdığımız sınıflara ait nesneler üzerinde operatörleri kullanmak isteriz. Bu durumda sınıfımızda bir takım değişiklikler yapmak zorundayız.

Bir örnek uygulama üzerinden operatörlerin aşırı yüklenmesini incelemeye çalışalım. Örneğimizin senaryosunda aşırı yükleme işlemini uygulamak için Price adında bir sınıf oluşturup bu sınıfa Cost adında bir property ekleyelim. İki farklı Price nesnesi üzerinden (+) gibi operatörleri aşırı yüklemeye çalışalım.

public class Price
{
      public double Cost { get; set; }

      public static double operator +(Price e1, Price e2)
      {
          return e1.Cost + e2.Cost;
      }
}

En basit gösterimi ile Price sınıfında (+) operatörünün aşırı yüklenmiş halini görüyoruz. Bir operatörün aşırı yüklenmesi bir takım kurallar içermektedir. Bunlar:

  • Operatör fonksiyonu static olmalıdır.
  • Operatör fonksiyonu, aşırı yüklenecek operatörün anahtar kelimesini belirtmelidir.
  • Operatör fonksiyonunun parametreleri, işlenecek tiplerdir.
  • Operatör fonksiyonunun geri dönüş türü belirlenmelidir.

Bu sınıf için (+) operatörünün kullanımı, şu şeklide opacaktır.

 Price p1 = new Price { Cost = 40.10 };
 Price p2 = new Price { Cost = 40.10 };

 var sum = p1 + p2; // sum = 80.20

Artık (+) operatörü, Price nesneleri için bir işleve sahip. Bu işlev, Price nesnesinin Cost parametrelerinin toplamını almasıdır.

Eğer aşırı yükleme işlemini yapmasaydık ve (+) operatörünü aynı şekliyle Price nesnesinde kullanmaya çalışsaydık şu şekilde bir hata alacaktık: “Operator ‘+’ cannot be applied to operands of type ‘OperatorOverrideApp.Price’ and ‘OperatorOverrideApp.Price

Price nesnesine int, double, float gibi built-in tipler ile toplamak istersek sadece işlenen argümanlarda şu şeklide bir değişiklik gerçekleştirmek yeterli olacaktır.

public static double operator +(Price e1, double e2)
{
     return e1.Cost + e2;
}

Bu şekilde, kendi sınıflarımızda operatörlerin aşırı yüklenmesi işlemini incelemeye çalıştık. Örnek uygulamaya ait kodlara buradan ulaşabilirsiniz.

Yeni Dizüstü Bilgisayarımı Satın Aldım

21 May

2008 yılından bu yana kahrımı çeken emektar laptopuma veda zamanı geldi çattı. Çünkü onu emekli edip yeni dizüstü bilgisayarımı satın aldım. Emektar makinam Datron marka olup TW7A modelinde ve zamanının 2.4Ghz  hızında en iyi işlemcilerine sahipti. Markasının Datron olması sebebiyle ben ona “Patron” diyordum.

Yeni makinam ise ASUS N56VZ. Son bir kaç haftadır bilgisayar araştırıyordum. Onu mu alsam bunu mu alsam derken en iyisi ben bu ASUS’u alayım diye karar kıldım. Asus için yakıştırmam ise “AL SUS” oldu. Gerçekten bu yakıştırmayı hakeden bir ürün. Şiddetle tavsiye ederim. Ürünü bir mağazanın “portakal rengi” indirim günlerinde inanılmaz bir fiyata yakaldım ve hemen satın aldım.

Emektar ve Yeni İşçi
Emektar ve Yeni İşçi

Özellik Karşılaştırması

Emektar DATRON Yeni ASUS
intel centrino 2.4 Ghz İntel i7 3630QM 2.4 Ghz
250 GB HDD 1 TB HDD
2GB RAM 16 GB RAM
512 MB Ekran kartı 4 GB Ekran Kartı
DVD Yazıcı Blue Ray Yazıcı

Mapping İşlemleri ve Automapper Performans Testleri

10 May

Programlama dünyasında nesneler arası aktarım yapılması amacıyla geliştirilmiş olan Automapper kütüphanesi üzerinde yaptığım performans sonuçlarını yazmak istedim.

C# kodu ile geliştirdiğim örnek uygulama üzerinde sırsıyla 10, 100, 1000, 10000 ve 100000 kayıt üzerinde üç farklı şekilde Mapping işlemi yapmayı denedim.

Örnek senaryoda Product adında bir sınıf düşünün. Bu sınıfın 10 farklı property üyesi olsun. Ben bu 10 üyeli Product tipini taşımak istemediğimden ProductSummary adında 2 üyesi olan bir sınıf oluşturuyorum.

public class Product
{
   public int id { get; set; }
   public string Name { get; set; }
   public string Color { get; set; }
   public string Model { get; set; }
   public string Size { get; set; }
   ...
   ..
   .
}

public class ProductSummary
{
   public int id { get; set; }
   public string Name { get; set; }
}

Doğal olarak Product nesnesini bir şekilde ProductSummary nesnesine aktarmalıyım. Bu işlemi Automapper kütüphanesi ile ve manuel olarak denediğimde ve süreleri milisaniye cinsinden ölçtüğümde ilginç rakamlarla karşılaştım.

List<Product> products = new List<Product>();

Kayıt sayısı sırayla 10, 100, 1000, 10000 ve 100000 olarak değiştiriliyor ve her seferinde Mapping işlemi deneniyor.

Mapping-1 (Yöntem-1 Foreach döngüsüyle tek tek Mapping işlemi)

foreach (var product in products)
{
    ProductSummary summary = Mapper.Map<Product, ProductSummary>(product);
}

10             kayıt için süre    121 milisecond
100          kayıt için süre    127 milisecond
1000       kayıt için süre    155 milisecond
10000     kayıt için süre    498 milisecond
100000  kayıt için süre    5298 milisecond

Mapping-2 (Yöntem-2 Kolleksiyonu direk mapping işlemine sokmak)

IEnumerable<ProductSummary> summary = Mapper.Map<IEnumerable<Product>,
                                    IEnumerable<ProductSummary>>(products);

10           kayıt için süre    133 milisecond
100         kayıt için süre    126 milisecond
1000      kayıt için süre    221 milisecond
10000    kayıt için süre    152 milisecond
100000  kayıt için süre    339 milisecond

Mapping-3 (Yöntem-3 Automapper kullanmadan manuel olarak nesneleri oluşturmak)

foreach (var product in products)
{
    ProductSummary summary = new ProductSummary();
    summary.id = product.Id;
    summary.Name = product.Name;
}

10           kayıt için süre    1 milisecond
100         kayıt için süre    1 milisecond
1000      kayıt için süre    2 milisecond
10000    kayıt için süre    4 milisecond
100000  kayıt için süre    42 milisecond

Mapping-4 (Yöntem-4 LINQ Extension metodlar yarımıyla mapping işleminin gerçekleştirilmesi)

var data = products.Select(summary=>
                 new ProductSummary{
                    Id= summary.Id,
                    Name = summary.Name
});

10           kayıt için süre    1 milisecond
100         kayıt için süre    1 milisecond
1000      kayıt için süre    1 milisecond
10000    kayıt için süre    1 milisecond
100000  kayıt için süre    1 milisecond

Mapping Raporları
Mapping Raporları

Bu sonuçlara göre Automapper kütüphanesi Mapping işlemlerinde biraz yavaş kaldığı aşikardır. En hızlı yöntemin LINQ Extension metodları yardımıyla Mapping işleminin olduğu ortaya çıkmaktadır. 100.000 kaydın mapping işlemine tabi tutulması 1 milisaniye sürmektedir. Aynı işlem Automapper kütüphanesi ile 5000 milisaniyeden fazla sürmektedir. Yani zaman probleminin olmadığı uygulamalarda Automapper kullanılabilir. Ancak işlemleri uzun sürede bitirmesi amacıyla yazılmış bir uygulama şu ana kadar hiç görmedim.

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

Asp.Net MVC JSON Model Bining

7 May

Asp.Net MVC mimarisinde yer alan model binding konusunu daha önceki yazılarda ele almıştık. Bu yazıda ise model binding işlemini JSON nesneleri ile uygylamaya çalışacağız. Web projelerinde ihtiyaç duyduğumuz  javascript tabanlı sorguları gerçekleştirmek için JSON nesnelerini .NET nesnelerine dönüştürmemiz gerekebilir. Request data olarak JSON nesnelerini POST edebilmeliyiz.

Örnek Uygulama

Örnek uygulama olarak bir ürün arama işlemini JSON formatındaki verileri bir Action metoda POST edeceğiz.

Öncelikli olarak Request ile gelen JSON fromatındaki veriyi deserialize ederek .Net nesnelerine dönüştürecek olan ModelBinder sınıfımızı oluşturmalıyız.

public class JsonModelBinder : IModelBinder
{
     public object BindModel(ControllerContext controllerContext,
                             ModelBindingContext bindingContext)
     {
          if (controllerContext == null)
             throw new ArgumentNullException("controllerContext");

          if (bindingContext == null)
             throw new ArgumentNullException("bindingContext");

          var serializer = new DataContractJsonSerializer(bindingContext.ModelType);
          var deSerialized = serializer.ReadObject(
                             controllerContext.HttpContext.Request.InputStream);

          return deSerialized;
    }

}

DataContractJsonSerializer sınıfının ReadObject metodu Request üzerinden ile gelen veriyi (InputStream), ModelBindingContext sınıfının ModelType parametresine göre uygun .Net tipine dönüştürür.

Şimdi de ModelBindingContext sınıfına gönderilecek olan tipi hazırlamalıyız.

[DataContract]
[ModelBinder(typeof(JsonModelBinder))]
public class JsonProductSearchRequest
{
     [DataMember]
     public string Name { get; set; }
     [DataMember]
     public string Color { get; set; }
}

System.Runtime.Serialization isim alanına dahil olan DataContract ve DataMember attribute tipleri sınıfları ve sınıf üyelerini serileştirilebilir hale getirmek için kullanılırlar. (Yeri gelmişken söylemekte fayda var; Bir tipi serileştirmek JSON, XML veya Binary şekillerde olabilmektedir. Biz örneğimizde JSON serileştirme üzerinde duracağız). JSonProductSearchRequest sınıfımızı, model binding sırasında ihtiyaç duyulan attribute olan ModelBinder ile imzalıyoruz, parametre olarak ise daha önceden hazırladığımız JsonModelBinder tipini gönderiyoruz.

Artık Controller tarafında ihtiyaç duyulan Action Metodları hazırlayabiliriz.

public class ProductController : Controller
{
   [HttpPost]
   public JsonResult JsonSearch(JsonProductSearchRequest request)
   {
       return null;
   }
}

JsonSearch Action metodu, daha önceden hazırladığımız JsonProductSearchRequest tipinde bir parametre almaktadır.

Şimdi hazırladığımız bu metoda fiddler yardımıyla bir istek (request) göndererek durumu incelemeye çalışalım.

Fiddler Json POST
Fiddler Json POST

Fiddler aracında Composer sekmesinden Request Tipini POST olarak seçiyoruz. Sunucudaki uygulama linkimizi girerek Request Body kısmına uygun JSON verisini giriyoruz. Execute butonuyla çalıştırdığımızda kodumuza geçip “break point” ile takip edersek:

Json Model Binder
Json Model Binder

Gönderdiğimiz verinin POST edildiğini rahatlıkla görebiliriz.

Bu şekilde etkili sonuç veren bir çözüme ModelBinding nimetlerinden faydalanarak ulaşmayı başardık. JSON tabanlı arama işlemlerini rahatlıkla bu şekilde gerçekleştirebiliriz. Ben bu örnekte View sayfalarıyla uğraşmamak adına fiddler aracından faydalanmayı uygun gördüm.

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

Asp.Net MVC Custom Controller Factory

4 May

Asp.net MVC mimarisini benim için değerli kılan özelliklerinden başında genişletilmeye uygun olarak tasarlanmış olması gelmektedir.

Bu yazımızda Asp.Net MVC yaşam alanına giren bir isteği(request) ilk karşılayan Controller mekanizmasının özelleştirilmesi üzerinde duracağız. MVC mimarisinde Controller tipleri belli kurallar dahilinde tanımlanmıştır. Bu kuralların dışına çıkmak istediğimizde kendi isteğimize göre özel kurallar oluşturarak sisteme dahil etmemiz gerekmektedir. Default olarak tanımlanmış Controller kurallarından biri de Controller sınıflarının kurucu metodları (constructor) parametresiz olmasıdır.

Controller
Controller

Bu yazımızda parametresiz constructor metodunu ihlal ettiğimizde karşılaşacağımız sorunlar ve çözümleri üzerinde duracağız.

Parametresiz Constructor Hatası
Parametresiz Constructor Hatası

Parametresiz constructor kuralını ihlal ettiğimizde hemen bir hata ile karşılaşırız. Burada yapmak istediğimiz IoC (Inversion of Control) mantığında Controller sınıfına dışarıdan bir nesne(securityService) enjekte etmektir. Bu işlem için piyasadaki Ioc kütüphanelerini kullanabiliriz. Piyasada şu anda kullanılan kütüphaneler widsor, structuremap, ninject,… şeklinde sıralanabilir. Şu anda konumuz olmasa da IoC kütüphanelerinin yaptığı işten hemen kısaca bahsedelim. IoC kütüphaneleri interface gibi soyut tiplere karşılık olarak belirlediğimiz somut sınıflara ait nesneleri ihtiyaç duyduğumuzda oluşturarak bize sunarlar. Bu sayede “new” anahtar sözcüğü ile Controller içinde nesne oluşturarak somut tiplere bağımlı kalmamış oluruz.

Bu kısa notun ardından kendi tasarladığımız ControllerFactory sınıfımızı oluşturmaya başlayalım.

public class IocControllerFactory : DefaultControllerFactory
{
    protected override IController GetControllerInstance(

    RequestContext requestContext, Type controllerType)
    {
         return (IController)ObjectFactory.GetInstance(controllerType);
    }
}

DefaultControllerFactory sınıfının GetControllerInstance metodunu ezerek Controller nesnesi oluşturma işlemini StructureMap IoC container kütüphanesine yükledik. StructureMap kütüphanesi, önceden tanımladığımız interface ve sınıf eşleştirmesini yaparak constructor parametresi olarak kullanılan interface tipine karşılık bir somut nesne sunmaktadır.

public static class ContainerBootstrapper
{
     public static void BootstrapStructureMap()
     {
         ObjectFactory.Initialize(x =>
                  x.For<ISecurityService>().Use<SecurityService>());
     }
}

ContainerBootstrapper static sınıfında tanımladığımız BootstrapStructureMap metodu içerisinde interface tipine karşılık bir somut sınıf belirlenmektedir. ISecurityService interface tipi için SecurityService somut tipini kullan demiş olduk.

Hazırladığımız düzeneği çalıştırabilememiz için son olarak Global.asax içerisinde son hamlelerimizi yapmamız gerekiyor.

protected void Application_Start()
{
    .....
    ....

    ContainerBootstrapper.BootstrapStructureMap();

    ControllerBuilder.Current.SetControllerFactory(new IocControllerFactory());

}

Öncelikle ContainerBootstrapper.BootstrapStructureMap(); metodu ile eşleştirme işlemini gerçeklştiriyoruz. Ardından ControllerBuilder sınıfı yardımyla kendi özel conrtoller factory tipimiz olan IocControllerFactory tipini sisteme tanıtıyoruz. Artık DefaultControllerFactory sistemden çıktı ve yeni oluşturduğumuz factory tipi sistemimize dahil oldu.

Parametreli COntroller Constructor
Parametreli COntroller Constructor

Programı çalıştırdığımızda IsecurityService tipine karşılık olarak bir SecurityService nesnesi oluşturulmuştur.

StructureMap IoC container kütüphanesi hakkında detaylı bilgiyi buradan bulabilirsiniz.

Adapter Tasarım Deseni (Design Pattern)

1 May

Adapter tasarım deseni, kodun bağımlılığını azaltmak amacıyla uygulanan kalıplardan biridir. Özellikle kurumsal bazlı projelerde modüler yapıda geliştirme yapıldığı düşünüldüğünde uyumluluğun sağlanması, gerekli şartlardan saedce biridir. Proje üzerinde çalışan geliştiriciler farklı modülleri hazırlayıp ortak bir noktada yazılıma monte edebilmelidir.

Adapter Tasarım Deseni
Adapter Tasarım Deseni

Yukarıdaki şemada “Client” tarafındaki kod biriminin soyut olan (interface veya abstract) “Target” kod birimini tanıması ve “Target” tipinden türetilen diğer tipleri tanımaması modülerliğin ve test edilebilirliğin sağlanabilmesi için gerekli esnekliği bize sunmaktadır. “Adapter” tarafındaki kod birimleri, “Target” tipinden türetilmektedir. Bu noktadaki implementasyonları N sayıda geliştirici yapabilmelidir.

Adapter Tasarım Örnek
Adapter Tasarım Örnek

Bu şemada “Client” kod olarak bir rapor servisi (ReportService) sunulmaktadır. ReportService Servis tipimiz sadece soyut olan “IReportProducer” tipini tanır. IReportService tipinin uygulandığı WordReportAdapter tipini tanımaz. WordReportAdapter tipi sadece Microsoft.Office kütüphanesini kullanarak Word dökümanı üretir.

İki farklı geliştirici olduğunu düşünecek olursak birine Word dökümanı üreten adaptörü, diğerine de PDF dökümanı üreten adaptörü yazdırabiliriz. Geliştiricilerimiz de ReportService tipiyle ilgilenmezler. Sadece IreportProducer tipini tanırlar ve bu tipi implemente ederek PDF ve Word raporu üreten sınıfları geliştirirler.

Örnek uygulama

Örnek uygulama olarak yukardaki şemanın C# kodu ile yazılmasını ele alabiliriz.

public interface IReportProducer
{
    void CreateReport(Report report);
}
public class ReportService
{
      private readonly IReportProducer reportProducer;
      public ReportService(IReportProducer reportProducer)

          this.reportProducer = reportProducer;
      }
     public void CreateReport()
      {
          reportProducer.CreateReport(new Report());
      }
}
public class WordReportAdapter : IReportProducer
{
      public void CreateReport(Report report)
      {
          // TR: Office DLL nesneleri yardımıyla raporu oluştur.
          // EN: Get Office DLL objects and create Report
      }
}

Bu tasarım sayesinde ReportService sınıfı test edilebilir hale getirilmiş oldu. Mock nesneler oluşturulup tast işlemini gerçekleştirmek basitleşti.

Eğer Word döküman raporunu üreten kodu ReportService sınıfı içerisinde yapsaydık;

  • Test edilebilirlikten uzaklaşacaktık.
  • Birden fazla developer ile bir işi geliştiremeyecektik.
  • Rapor servis tipi somut nesnelere bağımlı olacaktı.
  • Yeni bir rapor üretici geliştirilmek istediğimizde servis sınıfını bozmak zorunda kalacaktık.

Adapter tasarım kalıbının uygulanması gayet basittir. Tek amacı ise birbirini tanımayan tipleri interface gibi soyut tipler kullanarak birbiri ile çalışabilir hale getimektir.

Kaynak Kod: https://skydrive.live.com/redir?resid=2884CE0681105B31!147