|
Herşey Bir Nesnedir - 2 |
|
Gönderiliyor lütfen bekleyin... |
|
|
Önceki
makalemizde nesnenin öneminden bahsetmiş ve bir ev-ödevi ile konuyu bir
sonraki makalede devam ettirmek için sonlandırmıştık. Bu makalede yeni
bir konuya giriş yaparak sorumuzun cevabını bulmaya çalışacağız. Ama
önce Properties Windowdan bahsedelim. Delphi programcılarının "Object
Inspector" olarak bildiği, formumuza design-time da eklediğimiz
kontrollerin özelliklerini değiştirmemize yarayan penceredir..
Yukardaki şekilde TextBox componentine has bilgilerin PropertyGrid e nasıl
yansıtılacağını belirleyen alanları görüyorsunuz. Bu işlem ise
componenti yazarken programcı tarafından belirleniyor.
Örneğin :
Microsoft yazılımcıları TextBox componentinin renk, metin, hizalama,
font gibi şekilsel özelliklerini Appearance başlığı altında, yine
aynı şekilde Enter tuşuna basılınca alt satıra geç, küçük büyük harf
duyarlılığı olsun, yanlızca okunabilsin gibi componentin sergileyeceği
davranışı ile ilgili özelliklerini ise Behavior kategorisi
altında toplamış. Diğer kategorilerin incelenmesini ise size
bırakıyorum.
Birde seçilen özellik ile ilgili aşağıda detaylı bilgisini görüyorsunuz.
Text property için "The text contained in the control" yazan alan ise bu
özelliğin açıklamasını (Description) gösteriyor.
Bahsettiğim bu belirlemeyi sağlayan mekanizma ise Attribute tanımlama
ile oluyor. Kendi sınıflarınızı yazarken attribute leri kullanarak
sınıfınıza ait özelliklerin PropertyGrid te bu şekilde hiyerarşik bir
şekilde gösterilmesini sağlayabilirsiniz. Şimdi aşağıdaki TextBox
componentinden türettiğimiz kendi yazdığımız componenti inceleyelim.
public class MetinKutusu : TextBox
{
//private - protected değişkenler
[
Category("Goruntu"),
Description("Metni buraya yazınız"),
]
public string Metin //özellik adı
{
get { return base.Text; }
set { base.Text = value; }
}
}
Yukarıdaki componenti formunuza eklediğinizde PropertyGrid te bizim
Metin ismini verdiğimiz özelliğin görünmediğini göreceksiniz. Çünkü ön
tanımlı olarak bütün özelliklerin yukarıdaki bahsettiğim attributelerden
bahsetmediğim Browseable niteleyicisi false olarak kabul edilir.
Bu, sizin tanımladığınız bütün özelliklerin design aşamasında
PropertyGrid te değiştirilemeyeceği sadece çalışma zamanında (run-time)
değiştirilebileceği anlamına gelir. Design aşamasında da bu özelliğin
değerini değiştirmek isterseniz özelliğin Category ve Description
attribute tanımlamasının yanına Browseable(true) yazmanız yeterli
olacak.
[
Category("Goruntu"),
Description("Metni buraya yazınız"),
Browsable(true)
]
MetinKutusu ismini verdiğimiz componenti forma eklediğimiz zaman yandaki
PropertyGrid teki gibi bizim tanımladığımız özelliğinde eklendiğini
göreceğiz.
Buraya kadar herşey tamam olmalı. Çünkü
geçen makaledeki sorumuzun cevabına adım adım yaklaşıyoruz. Hangi
makale, ne sorusu? diye soranlar varsa işte adres burada.
http://www.csharpnedir.com/makalegoster.asp?MId=312. Devam etmeden,
önceki makaleyi okumanızı tavsiye ediyorum.
Attributelere geri donelim. Attribute sınıfı System isim uzayında
tanımlı olup sınıfınızın diğer sınıflardan ayrılan bazı niteliklere
sahip olmasını sağlar. Kendi attributelerimi nasıl tanımlayacağım ve
nasıl kullanacağım (diğer sınıflardan farkını nasıl ayırt edeceğim?)
diye soruyorsanız okumaya devam.
Öncelikle Attribute sınıfından yeni bir sınıf türetip ek özelliklerinizi
ekleyeceksiniz. Aşağıda saçma olmakla beraber anlaşılır olacağını
düşündüğüm şöyle bir örnek vereyim. Yazdığınız componentin lisanslı
olmaması halinde componentinizi yasal olmayan yollarla ele geçiren bir
kişiyi uyarmayı sağlayacak bir attribute tanımlaması yapmak istediğinizi
düşünelim;
using
System;
[AttributeUsage(AttributeTargets.Class |
AttributeTargets.Struct)]
public class LisansAttribute :
Attribute
{
bool lisansli;
// -> true : lisanslı, false : lisanslı değil
public LisansAttribute(bool
Lisansli) : base()
-> Temel Attribute sınıfının parametre almayan default
constructori
{
this.lisansli =
Lisansli;
}
public bool Lisansli
{
get {
return lisansli; }
set { lisansli =
value; }
}
} |
Tanımladığımız bu attribute nasıl
kullanılacak ??
Yukarıda nasıl Category, Description veya Browsable attributelerini
kullandıysak öyle kullanacağız. Ama ondan önce birşey daha ekleyelim.
Sınıfın üzerinde tanımladığımız şu AttributeUsage da ne acaba?
diyorsanız, Cevap : Bu Attribute un kullanılacağı yerleri belirtiyor. Biz
sadece sınıf ve yapılarda kullanmak istiyoruz. eğer sadece property
lerde kullanmak istersek
[AttributeUsage(AttributeTargets.Property)] dememiz gerekecek.
Şimdi bu attributeu kullanan bir sınıf yazalım.
[Lisans(false)]
public class Lisansli
{
...
...
} |
Attribute adımız LisansAttribute idi ama
Attribute sonekini yazmamıza gerek yok. LisansAttribute değerini (bizim
örneğimizde : false) okuyabilmek için System.Reflection uzayını
kullanacağız.
Bu konuda gerekli ön-bilgiyi almak için Burak Şenyurt arkadaşımızın makalesini de
incelemenizi tavsiye ederim.
http://www.csharpnedir.com/makalegoster.asp?MId=172.
Hatırlarsanız önceki makalemde object sınıfının öneminden
bahsetmiştik. İşte yine başlıyoruz. Parametre olarak object
göndereceğiz, GetType() metodu ile objnin tipini alıp System.Reflection
uzayında tanımlı bizim için gerekli olacak GetCustomAttributes metodu
ile bu obj de tanımlı attribute leri elde edeceğiz. Bu metodun bool olan
ikinci parametresi true ise, kalıtım zinciri üzerindeki tüm temel
sınıfların niteliklerini dahil et anlamındadır. Aksi halde sadece
belirtilen tip tarafından tanımlanan nitelikler bulunacaktır.
private void Lisanslimi(object obj)
{
Type objType = obj.GetType();
LisansAttribute[] lisanslar = (LisansAttribute[])
objType.GetCustomAttributes(typeof(LisansAttribute), true);
if ( lisanslar.Length > 0) // LisansAttribute
belirtilmiş ise lisanslar dizisinin uzunluğu sıfırdan büyük
olmalıdır.
{
LisansAttribute lisans = lisanslar[0];
// Tek Lisans tanımlı. 0. indeksteki
lisansı al.
if ( lisans.Lisansli ) //
LisansAttribute unun Lisanslı propertysi bu objectin lisanslı
olup olmadığına boolean (true - false) bir ifadeyle cevap
verecek.
// object
lisanslı
else
// object
lisanslı değil, lütfen telefon ile lisans numarası alınız.
}
else
throw new Exception("LisansAttribute tanımlı değil");
//sınıf tanımından önce
[Lisans(true|false)]
belirtilmemiş.
} |
Buraya kadar kafanıza takılan bir nokta
yok ise geçen makalemizin cevabı için adım adım ilerleyelim.
Bilindiği gibi bir veritabanında tablo gruplanmış veriler kümesinden
oluşmaktadır. Veriler ise alanlar ve herbir alanın veri tipi ile ifade
edilir. Örneğin;
Uyelerinizin kaydını veritabanında tutmak isterseniz, UYELER adında bir
tablo ve bu tablodaki verilerin ise AD, SOYAD, EMAIL, DOGUM_TARIHI,
KULLANICI_ADI, SIFRE gibi alanlardan olusmasini istersiniz. ve unique
primary key alanı muhtemelen ID (int) olacak.
AD, SOYAD, EMAIL, KULLANICI_ADI ve SIFRE -> string
DOGUM_TARIHI ise DateTime olacaktır.
Bu nedenle Sınıfları da birer tablo olarak düşünemez miyiz acaba?
public class UYE
{
string ad;
string soyad;
string email;
string kullanici_adi;
string sifre;
DateTime dogumTarihi;
public string Ad
{
get { return ad; }
set { ad = value; }
}
public string Soyad
{
get { return soyad; }
set { soyad = value; }
}
....
public DateTime DogumTarihi
{
get { return dogumTarihi; }
set { dogumTarihi = value; }
}
} |
Pekala bu sınıftan oluşturduğum bir
kaydı veritabanına nasıl yazacağım?
public void YeniUye()
{
UYE uye = new UYE();
uye.Ad = "Orhan";
uye.Soyad = "Albay";
...
uye.DogumTarihi = "11.04.1980";
// uye sınıfını oluşturdum ama nasıl kayıt yapacam tabloya ????
} |
Cevap : Attribute
kullanarak.
İşte başlıyoruz. Önce
attribute tanımlamalarımızı yapalım. DatabaseTableAttribute sadece class
ve struct larda kullanılacak. DataColumnAttribute ise sadece sınıfın
propertylerinde kullanılacak.
[AttributeUsage(AttributeTargets.Class |
AttributeTargets.Struct)]
public class
DatabaseTableAttribute : Attribute
{
string tabloAdi;
public DatabaseTableAttribute(string
TabloAdi) : base()
{
this.tabloAdi = TabloAdi;
}
public string
TabloAdi
{
get {
return tabloAdi; }
set { tabloAdi =
value; }
}
}
[AttributeUsage(AttributeTargets.Property)]
public class
DataColumnAttribute : Attribute
{
string kolonAdi;
bool primaryKey = false;
public DataColumnAttribute(string
KolonAdi) : base()
{
this.kolonAdi =
KolonAdi;
}
public string
KolonAdi
{
get {
return kolonAdi; }
set { kolonAdi =
value; }
}
public bool
PrimaryKey
{
get {
return primaryKey; }
set { primaryKey =
value; }
}
} |
Şimdi attributelerimizi bu sınıfa
uygulayalım.
[DatabaseTable("UYELER")]
public class UYE
{
int id;
string ad;
string soyad;
string email;
string kullanici_adi;
string sifre;
DateTime dogumTarihi;
[DataColumn("ID", KeyField=true)] //
KeyField=true , primary key
public int ID
{
get { return id; }
set { id = value; }
}
[DataColumn("AD")]
public string Ad
{
get { return ad; }
set { ad = value; }
}
[DataColumn("SOYAD")]
public string Soyad
{
get { return soyad; }
set { soyad = value; }
}
....
[DataColumn("DOGUM_TARIHI")]
public DateTime DogumTarihi
{
get { return dogumTarihi; }
set { dogumTarihi = value; }
}
} |
Şimdi bu sınıftan oluşan bir nesneyi
database ten çekmek için gerekli olacak SELECT cümlesini ve bu nesneyi
tabloya kaydetmek için gerekli olacak INSERT, silmek için DELETE ve
güncellemek için UPDATE cümlelerinin nasıl oluşturulacağını inceleyelim.
public static string
GetSelectCommandTextForObject(Type objType, params object[]
parametreler)
{
StringBuilder sb = new StringBuilder();
// DatabaseTable Attributelerini al.
DatabaseTableAttribute[] databaseTables =
(DatabaseTableAttribute[])
objType.GetCustomAttributes(typeof(DatabaseTableAttribute),
true);
if(databaseTables.Length > 0)
{
sb.Append("SELECT ");
foreach(PropertyInfo property in
objType.GetProperties(BindingFlags.Public
| BindingFlags.Instance)) //sadece
bu sınıfın property lerini al. Temel sınıfınkilerini değil.
{
//
Herbir property için DataColumn Attributelerini al
foreach(DataColumnAttribute field in
property.GetCustomAttributes(typeof(DataColumnAttribute), true))
{
sb.Append("[" + field.KolonAdi + "]");
sb.Append(", ");
}
}
sb.Remove(sb.Length-2, 2);
sb.Append(" FROM ");
sb.Append(databaseTables[0].TabloAdi);
// tek DatabaseTable Attribute tanımlı. 0.
indekstekini al.
if(parametreler != null &&
parametreler.Length > 0)
{
sb.Append(" WHERE ");
for(int i=0;
i<parametreler.Length; i++)
{
sb.Append(parametreler[i].ToString());
sb.Append(" AND ");
}
sb.Remove(sb.Length-5, 5);
}
}
else
throw new
Exception("DataTable belirtilmemiş");
return sb.ToString();
}
Bu static metodun aldığı 1. parametre object tipi , 2. parametre
ise parametreler.
Kullanımı ve Ürettiği SELECT cümlesi:
object[] parametreler = new object[] {"ID=1"};
string SelectText =
GetSelectCommandTextForObject( typeof(UYE), parametreler );
SONUC : SelectText = "SELECT ID,
AD, SOYAD, EMAIL, KULLANICI_ADI, SIFRE, DOGUM_TARIHI FROM UYELER
WHERE ID = 1";
Bu select cümlesini DataAdapter
SelectCommand.CommandText ine gönderir ve Execute ederseniz
tablodan ilgili kaydı çekersiniz.
Diğer cümlelerin oluşturulması ise Select cümlesinin
oluşturulması ile hemen hemen aynı. Örnek kodları
indirebilirsiniz. |
Sürekli farklı sınıflarla çalışıyor iseniz ve bu sınıfların
tablolarla ilişkisi varsa bu şekilde attribute yazıp sınıflara
uygulayıp dinamik olarak sınıflardan ilgili SQL cümlesini
oluşturup tabloya kaydedebilirsiniz. Bu şekilde kendi
BusinessObject lerinizi oluşturup her defasında yeniden tanım
yapmanıza gerek kalmadan programınızın ince noktalarına
yoğunlaşabilirsiniz. Zaman tasarrufu sağlamış olursunuz. Gelecek makalede TreeView`e farklı tipten nesneleri nasıl
ekleriz? konusunu işleyeceğiz. Görüşmek üzere.
Orhan ALBAY
[email protected]
Makale:
Herşey Bir Nesnedir - 2 C#, Visual C# ve .NET Orhan Albay
|
|
|
-
-
Eklenen Son 10
-
Bu Konuda Geçmiş 10
Bu Konuda Yazılmış Yazılmış 10 Makale Yükleniyor
Son Eklenen 10 Makale Yükleniyor
Bu Konuda Yazılmış Geçmiş Makaleler Yükleniyor
|
|