Kategori Arşivi C#

C # 5 Caller Info Attributes Kullanımı ve Eski Versiyonlar İçin Bir Yöntem Önerisi

Merhabalar.

C# 5’te(yani .NET Framework 4.5’ta) gelen Caller Info özellikleriyle herhangi bir metodu nereden çağırdığımıza dair bilgilere erişebiliyoruz.

Bu da özellikle loglama ve izleme(örneğin SQL Server Profiler kullanımı) işlemlerinde büyük fayda sağlıyor.

Syntax şu şekilde :

public void NeredenGeldim(string parametre, 
                                             [CallerMemberName]string cagiranMetodAdi = "", 
                                             [CallerFilePath]string cagiranDosyaYolu = "", 
                                             [CallerLineNumber]int cagiranSatirNumarasi = 0)

Bu attributeleri şu şekilde açıklayabiliriz:
CallerMemberName: Bu metodun hangi metoddan çağırıldığı bilgisini,
CallerFilePath: Bu metodun çağırıldığı dosyanın dosya yolunu,
CallerLineNumber: Bu metodun çağırıldığı satır numarasını almamızı sağlar.

Örneklere başlamadan önce NOT: Resimleri üzerlerine tıklayarak büyütebilrsiniz.

Şu örneği inceleyerek oldukça basit bir kullanımı olduğunu görebilirsiniz:

static void Main(string[] args)
{
   MetodCagir();
}

private static void MetodCagir()
{
   NeredenGeldim("Bir metodun serancamı:");
}

public static void NeredenGeldim(string parametre, [CallerMemberName]string cagiranMetodAdi = "", [CallerFilePath]string cagiranDosyaYolu = "", [CallerLineNumber]int cagiranSatirNumarasi = 0)
{
   Console.WriteLine(parametre);
   Console.WriteLine("Çağıran Metodun Adı : " + cagiranMetodAdi);
   Console.WriteLine("Çağıran Metodun Dosya Yolu : " + cagiranDosyaYolu);
   Console.WriteLine("Çağıran Metodun Satır Numarası : " + cagiranSatirNumarasi);
   
   Console.Read();
}

Çıktı:

Buraya kadar her şey güzel. Ama .NET Framework’ün eski versiyonlarında bu “attribute”leri kullanamıyoruz. Bunun için yapabileceğimiz şey tüm versiyonlarda bulunan aslında fazlasıyla aşina olduğumuz bir sınıfı kullanacağız: StackTrace!

İlk etapta eski versiyonlar için metodu oluşturalım:

public static void NeredenGeldimEskiVersiyonlar(string parametre, string cagiranMetodAdi = "", string cagiranDosyaYolu = "", int cagiranSatirNumarasi = 0)
{
   StackTrace st = new StackTrace(true);
   StackFrame[] frames = st.GetFrames();

   Console.WriteLine(parametre);
   Console.WriteLine("Çağıran Metodun Adı : " + cagiranMetodAdi);
   Console.WriteLine("Çağıran Metodun Dosya Yolu : " + cagiranDosyaYolu);
   Console.WriteLine("Çağıran Metodun Satır Numarası : " + cagiranSatirNumarasi);
 
   Console.Read();
}

Burada StackTrace’in her bir “frame“i aslında hata mesajlarında gördüğümüz satırları ifade ediyor ve aşağıdaki gibi gözüküyor:

İncelediğimizde içinde bulunduğuz metoddan başlayarak hiyerarşik bir şekilde metodların “frame” dizisinde listelendiğini görüyoruz.

Gördüğünüz gibi olay “Caller Info Attributes”teki kadar kolay değil. Geldiğimiz metodu tespit etmek için bir şekilde dizinin elemanlarını bir şekilde filtrelememiz lazım.

Bunun için de “frame”lerin içeriğine biraz daha yakından bakalım. Örneğin bizim aradığımız metod olan “MetodCagir“ı içeren “frame”i inceleyelim:

Burada “Frame“in altında “DeclaringType“ı ve onun “property“leri arasında ise “Name” ve “FullName” alanlarını görüyoruz. “FullName”den yararlanarak metodumuzu çağıran programı filtreleyebiliriz. Örneğimizde hepsi “MerhabaDunya.Program” olsa da kurumsal programlarda pek çok farklı proje entegre bir şekilde çalıştığı için farklı isimler bulunabilir bu kısımda.

Bu yüzden ilk etapta bir LINQ sorgusuyla “FullName”e göre filtreleyip neler olduğuna bakıyorum.

“frames” değişkenin atamasını güncelleyelim:

StackFrame[] frames =
 st.GetFrames()
 .Where(s => s.GetMethod().DeclaringType.FullName.Contains("MerhabaDunya.Program"))
 .ToArray();

Örneğe göz atmadan önce bir NOT: Bu arada ben LINQ sorgusu kullanacağım için .NET Framework 3.5 da çalıştırıyorum programı. LINQ sorgusuna ihtiyacınız yoksa daha alt versiyonlarda da bu yöntemi kullanabiliyorsunuz.

Şimdi debug modda “frames”e bakalım tekrar:

Görüldüğü üzere 3 metod kaldı. (Bu da demek oluyor ki dışarıda kalan 4 metod programımıza değil .NET Framework’e ait metodlardı.)

Bu metodlar da sırasıyla:

  • NeredenGeldimEskiVersiyonlar(İçinde bulunduğumuz metod)
  • MetodCagir(Metodumuza çağıran, asıl aradığımız metod)
  • ve Main metodu.

Artık filtreleme yaptığım sorguya bir şart daha ekleyerek aradığım “frame”e ulaşabilirim:

“Metod ismi ‘NeredenGeldimEskiVersiyonlar’ olmayan ilk ‘frame’i getir ve bilgilerini yazdır.”

Yazıyı daha fazla uzatmadan kodun son haline bakalım:

public static void NeredenGeldimEskiVersiyonlar(string parametre, string cagiranMetodAdi = "", string cagiranDosyaYolu = "", int cagiranSatirNumarasi = 0)
{
   StackTrace st = new StackTrace(true);
   StackFrame[] frames = st.GetFrames();
   StackFrame frame = new StackFrame();

   if (frames != null)
   {
      frame = frames.FirstOrDefault(s => s.GetMethod().DeclaringType.FullName.Contains("MerhabaDunya.Program") && s.GetMethod().Name != "NeredenGeldimEskiVersiyonlar");
      cagiranMetodAdi = frame.GetMethod().Name;
      cagiranDosyaYolu = frame.GetFileName();
      cagiranSatirNumarasi = frame.GetFileLineNumber();
   }
 
   Console.WriteLine(parametre);
   Console.WriteLine("Çağıran Metodun Adı : " + cagiranMetodAdi);
   Console.WriteLine("Çağıran Metodun Dosya Yolu : " + cagiranDosyaYolu);
   Console.WriteLine("Çağıran Metodun Satır Numarası : " + cagiranSatirNumarasi);

   Console.Read();
}

Ve çıktı:

Gördüğünüz üzere aslında C# 5’te hayatımıza giren bir çözüme eski versiyonlarda ulaşmak için bir “workaround” çözüm geliştirdim. Tahmin edeceğiniz üzere bu gerçek hayatta karşılaştığım bir problemi aşmak için bulduğum çözüm. Bundan daha temiz bir çözüm de olabilir elbette. Benden şimdilik bu kadar.

Kendinize çook iyi davranın.

 Bu sayfa 409 kez görüntülendi

It's only fair to share...Share on LinkedInShare on FacebookShare on Google+Tweet about this on TwitterShare on Tumblr

C# Gerçek Hayat Örneği : Reflection ve Expression Tree

Merhaba.

Bu yazıda C#’ın ileri diyebileceğimiz bir kaç özelliğini kullandığım bir örnekten bahsedeceğim. Bir konuyu anlatmaktan ziyade ihtiyaç duyduğumuz senaryoyu nasıl gerçekleştirdiğimi anlatacağım. İnternette ciddi bir araştırma zamanı geçirdiğim için paylaşma ihtiyacı hissettim. Ama nasip olursa bu konular, özellikle de Reflection hakkında bir kaç giriş makalesi yazma planım var.

Asıl konumuza gelecek olursak.. İhtiyacımız olan karışık bir senaryoyu gerçekleştirmek için yoğun bir mücadele sonucu aşağıdaki metodları yazdım.

Öncelikle sistemimizde bir proxy yapısı var. Proxy’ye interface i vererek servis metodlarının remote çalıştırılmasını sağlıyoruz.

Örnek verecek olursak.. Amacım kod içerisinde kullanımı aşağıdaki gibi olan yapıyı çalışma zamanında oluşturup çalıştırmak.

using (var service = new Proxy<IUrunler>())

{

   var response = service.Execute<Response<List<Urunler>>>(srv => srv.GetUrunler());

   object list = response.Value;

   //Diğer kodlar

}

Burada proxy sınıfıma ait “Execute” metodu parametre olarak gönderilen “Action”ı çalıştırıp “Response<T>” tipinde dönüş yapan bir metod.

Bahsettiğim gibi bu scripti dinamik olarak oluşturmam lazım. Lakin zorluk şu ki; buradakilerden “IUrunler” sınıfını da, “Response<List<Urunler>>” tipini de, “srv => srv.GetUrunler()” ifadesini de bilmiyorum ve çalışma zamanında alabiliyorum.

Burada ilk olarak “srv => srv.GetUrunler()” ifadesini oluşturmam gerekiyor. Bunun için yazdığım metod aşağıda.

 private Expression CreateExpression(Type interfaceType, MethodInfo method)

{

   ParameterExpression parameter = Expression.Parameter(interfaceType, "srv");

   Expression callExpression = Expression.Call(parameter, method.Name, null, null);

   Expression lambdaExpression = Expression.Lambda(callExpression, new ParameterExpression[] { parameter });

   return lambdaExpression;

}

Metodun parametrelerini yukarıdaki “IUrunler” örneği üzerinden açıklayacak olursam:

interfaceType: “IUrunler” vb. sözkonusu interface in tipi.

method: “GetUrunler()” metoduna ait Reflection ile elde edilmiş “MethodInfo” nesnesi.

İlk önce lambda ifademizde parametre olarak “srv” kullanacağımı belirtiyorum. Daha sonra “call” edilecek metodun ismini(GetUrunler) vererek callExpression ifadesini elde ediyorum.  Burada Expression sınıfına ait tam 14 adet “Call” metodundan parametre olarak methodName alan Call metodunu kullandım (public static MethodCallExpression Call(Type type, string methodName, Type[] typeArguments, params Expression[] arguments);).

“Expression”ımda kullanacağım elemanlarımı elde ettikten sonra bu alemanlarla Lambda Expression’ı oluşturmaya geldi sıra. Bunun için de yine Expression sınıfına ait 18 adet Lambda metodundan parametre olarak yalnız “Expression Body” ve “ParameterExpression” dizisi alan metodu kullanıyorum(public static LambdaExpression Lambda(Expression body, params ParameterExpression[] parameters);)

Şu ana kadar en üstte verdiğim örnekteki Lambda expression(“srv => srv.GetUrunler()”) ifadesini oluturmuş olduk. Scriptin kalan kısmını elde etmek için bu lambda expression ı da parametre olarak alan yeni bir metod yazıyorum:

private object GetResponseValue(Type interfaceType, Type methodReturnType, Expression expression)

{

   var proxyType = typeof(Proxy<>);

   var service = proxyType.MakeGenericType(interfaceType);

   string methodSignature = "TResponse Execute[TResponse](System.Linq.Expressions.Expression`1[System.Func`2[" + interfaceType.FullName + ",TResponse]])";

   MethodInfo executeMethodInfo = service.GetMethods().Single(mi => mi.ToString() == methodSignature);

   MethodInfo executeGeneric = executeMethodInfo.MakeGenericMethod(methodReturnType);

   var instanceClass = Activator.CreateInstance(service);

   var response = executeGeneric.Invoke(instanceClass, new object[] { expression });

   object list = response.GetType().GetProperty("Value").GetValue(response, null);

   return list;

}

 

Bu metodda ekstra parametre olarak “methodReturnType” var ve bu “GetUrunler” metodunun dönüş tipini yani “Response<List<Urunler>>” değerini ifade ediyor.

Oluşturmamız gereken proxy nesnesi ve çağıracağımız “Execute” metodu generic yapılar olduğu için bunları reflection ile oluştumamız gerekiyor.

İlk etapta “service” instanceını oluşturabilmek için “Proxy<>” nesnesinin tipini alarak bundan yine reflection ile generic “service” tipini elde ediyorum.

Execute metodunun farklı overload ları olduğu için direkt kullanacağım metodun imzasını belirterek MethodInfo’sunu elde ediyorum. Kullanacağım metod da generic olduğu için metodun dönüş tipini belirterek ve “MakeGenericMethod” kullanarak “Execute” metodunun generic versiyonunu oluşturuyorum(MethodInfo executeGeneric = doActionMethodInfo.MakeGenericMethod(methodReturnType)).

Sonrasında “Activator.CreateInstance“ yardımıyla “service” instance ımı oluşturuyorum.

..ve oluşturduğum instance yardımıyla, expression parametresini de göndererek metodu invoke ediyorum, sonucu response değişkenine atıyorum.

Son olarak da “respons”un “Value” propertysini list değişkenime atıyorum.

Umarım açıklayıcı ve faydalı bir anlatım olmuştur.

Kendinize çook iyi davranın…

 

 Bu sayfa 664 kez görüntülendi

It's only fair to share...Share on LinkedInShare on FacebookShare on Google+Tweet about this on TwitterShare on Tumblr

IF Enflasyonundan Kurtulmak İçin Dictionary Kullanımı

Merhabalar.

Daha önce temel manada Dictionary kullanımından bahsetmiştim.

Dictionary yapıları anahtar-değer(key-value) ikilisiyle içinde değer tutan generic yapılar. Burada farklı bir kullanımından bahsetmek istiyorum.

Dictionary kullanırken value olarak method atayabiliyoruz.

Atamak istediğimiz bu metod geriye değer dönen bir metod olacaksa Func<parametre1,parametre2.., return_tipi> ifadesiyle;
değer dönmeyecek bir metod olacaksa Action<parametre1,parametre2….> ifadesiyle set ediyoruz.

Bilhassa IF enflasyonu olan yerlerde bu şekilde gayet temiz bir iş yapabiliyoruz.

Şimdi bir banka için, mesela combobox’tan seçilip gönderilen değerlere göre, çeşitli raporlar hazırlayan aşağıdaki gibi bir metodumuz olsun:

private void RaporHazirla(int raporTuru)
{
	if (raporTuru == 1)
	{
		SubeBazliGunlukIslemRaporu();
	}
	else if (raporTuru == 2)
	{
		PersonelBazliGunlukIslemRaporu();
	}
	else if (raporTuru == 3)
	{
		MusteriBazliGunlukIslemRaporu();
	}
	else if (raporTuru == 4)
	{
		ToplamGunlukIslemRaporu();
	}
	else if (raporTuru == 5)
	{
		MessageBox.Show("Bu rapor 01.01.2015 tarihinden itibaren verilememektedir.");
	}
}

Burada bir Dictionary oluşturup, key olarak raporTuru‘nu, value olarak da rapor oluşturan metodları ekleyebilirim.

Ama burada bir problemimiz var! Son casede bir metod çağırılmıyor. Ama buradan da bir metod çağırmamız gerekiyor.

Yani:

private void RaporYokUyari()
{
    MessageBox.Show("Bu rapor 01.01.2015 tarihinden itibaren verilememektedir.");
}
private void RaporHazirla(int raporTuru)
{
	if (raporTuru == 1)
	{
		SubeBazliGunlukIslemRaporu();
	}
	else if (raporTuru == 2)
	{
		PersonelBazliGunlukIslemRaporu();
	}
	else if (raporTuru == 3)
	{
		MusteriBazliGunlukIslemRaporu();
	}
	else if (raporTuru == 4)
	{
		ToplamGunlukIslemRaporu();
	}
	else if (raporTuru == 5)
	{
		RaporYokUyari();
	}
}

gibi.

Artık Dictionary’mi oluşturabilirim. Global değişken olarak oluşturuyorum:

Dictionary<long?, Action> _dictRaporlar = new Dictionary<long?, Action>();

Burada value’yu Action tipinde tanımlamam demek, ekleyeceğim metodların tamamının void olması demek.
Eğer örneğin 2 int parametre alıp string bir sonuç dönen metodlar kullanacaksam(tabi bu defa da metodların tamamının parametre tipleri ve dönüş tipi aynı olmak zorunda. Ama object kullanılarak biraz esnetilebilir.) Action yerine Func<int,int,string> yazmam gerekirdi.

Her neyse şimdi Dictionary’nin içeriğini oluşturalım:

private void raporDictionaryOlustur()
{
	_dictRaporlar[1] = new Action(SubeBazliGunlukIslemRaporu);
	_dictRaporlar[2] = new Action(PersonelBazliGunlukIslemRaporu);
	_dictRaporlar[3] = new Action(MusteriBazliGunlukIslemRaporu);
	_dictRaporlar[4] = new Action(ToplamGunlukIslemRaporu);
	_dictRaporlar[5] = new Action(RaporYokUyari);
} 

Son tahlilde RaporHazirla metodumu aşağıdaki gibi ziyadesiyle sade bir şekilde düzenliyorum:

private void RaporHazirla(int raporTuru)
{
	 _dictRaporlar[raporTuru].Invoke();
}

Kendinize çook iyi davranın.

 Bu sayfa 1057 kez görüntülendi

It's only fair to share...Share on LinkedInShare on FacebookShare on Google+Tweet about this on TwitterShare on Tumblr

C#’ta Dictionary Kullanımı

Merhabalar.

Bu yazıda temel manada C#’ta dictionary kullanımından bahsetmeye çalışacağım.

Fırsat bulursam ileride daha detaylı ele almayı düşünüyorum.

Nedir?

Adından anlaşılacağı üzere sözlüğe benzetilen, key-value ikilisini içeren “generic” bir yapı.

Tanımı şu şekilde yapılır:


Dictionary<TKey, TValue> d = new Dictionary<TKey, TValue>();

Buradaki hem key hem de value kısmı herhangi bir obje(primitive tipler, nesne, delege/metod vb.) alabilir.

Aşağıda basit bir örnek var:


using System;

using System.Collections.Generic;

class Program
{
    static void Main()
    {
        Dictionary<int, string> d = new Dictionary<int, string>(){
            {1,"Ahmet"},
            {2, "Mehmet"},
            {3,"Muhammed"}};

        Console.WriteLine(d[1]);
    }
}

Çıktı: Ahmet

Üstte söylediğim gibi key ve value kısımlarına farklı objeler set edilebilir.

Örneğin oluşturduğumuz bir “Musteri” sınıfının nesnesini set edelim:


using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
         Musteri must1 = new Musteri(1, "Muhammed", "Hilmi");
         Musteri must2 = new Musteri(7, "Ahmet", "Koca");
         Musteri must3 = new Musteri(12, "Mehmet", "Kara");
         Musteri must4 = new Musteri(15, "Mustafa", "Kılıç");

         Dictionary<int, Musteri> musteri = new Dictionary<int, Musteri>();

         musteri.Add(must1.Id, must1);
         musteri.Add(must2.Id, must2);
         musteri.Add(must3.Id, must3);
         musteri.Add(must4.Id, must4);

         Console.WriteLine("Id : " + 1 + ", Ad : " + musteri[1].Ad + ", Soyad : " + musteri[1].Soyad);
}

public class Musteri
{
    public Musteri(int id,string ad,string soyad)
    {
        Id = id;
        Ad = ad;
        Soyad = soyad;
    }
    public int Id { get; set; }
    public string Ad { get; set; }
    public string Soyad { get; set; }
}

Çıktı: Id : 1,Ad : Muhammed, Soyad : Hilmi

 

 Bu sayfa 2604 kez görüntülendi

It's only fair to share...Share on LinkedInShare on FacebookShare on Google+Tweet about this on TwitterShare on Tumblr

DataGridView to DataTable

Merhabalar.

C#’ta DataGridView’in içeriğini DataTable’a kopyalama işlemi için 2 farklı durumla karşılaşabilirsiniz.

1-) Eğer DataGridView’in DataSource’una atama yapılmışsa, aşağıdaki 2 yöntemden herhangi biriyle içeriği kopyalayabiliyoruz(DataGridView’in ismi dgv):

DataTable dt = new DataTable();
 dt=dgv.DataSource as DataTable;

veya

DataTable dt = new DataTable();
 dt=(DataTable)(dgv.DataSource);

2-) DataSource’a atama yapılmadan, mesela formdan veri girişiyle DataGridView’in içeriği dolduruluyorsa DataSource null gelir. Dolayısıyla kopyalama işlemini üstteki yöntemlerle yapamayız. Bu durumda aşağıdaki gibi basit bir metod yazarak işimizi halledebiliriz:

public DataTable DataGridViewToDataTable(DataGridView dgv)
{
   DataTable dt = new DataTable();

   //Column mapping. Benim tüm kolonlarımın tipi string olduğu için buradaki
   //gibi basit bir foreach ile kolonları ekliyorum.
   //Eğer kolonlarınız farklı tipler içeriyorsa muhtemelen tek tek map yapmanız
   //gerekecektir.
   foreach (DataGridViewColumn dc in dgv.Columns)
   {
        dt.Columns.Add(dc.Name, typeof(string));
   }

   foreach (DataGridViewRow dgvRow in dgv.Rows)
   {
        DataRow dr = dt.NewRow();

        for (int i = 0; i < dgv.ColumnCount; i++)
        {
             if (dgvRow.Cells[i].Value != null)
                 dr[i] = dgvRow.Cells[i].Value.ToString();
        }

        //Bendeki DataGridView'e veri girişi yaparken, her satıra yazı yazmaya
        //başladığımda altında otomatik boş bir satır üretiyor.
        //Bu boş satırın DataTable'a eklenmemesi için bu kontrolü koyuyorum.
        if (!string.IsNullOrEmpty(dr[0].ToString()))
             dt.Rows.Add(dr);
        }

        return dt;
}

Kendinize çook iyi davranın.

 
Bu sayfa 1363 kez görüntülendi

It's only fair to share...Share on LinkedInShare on FacebookShare on Google+Tweet about this on TwitterShare on Tumblr