Bana hem eğitimler sırasında hem de bireysel olarak o kadar çok soruldu ki sanıyorum bu konuda birşeyler mutlaka yazmam lazım. Interface kavramının ne olduğunu buradaki yazıda anlatmaya çalışmıştım. Ancak buradaki yazı sadece genel olarak interface kavramını anlatıyor ve bir iki örnek ile konu bitiyordu.
Anladığım kadarı yazı biraz eksik kalmış. Çünkü interface'ler sadece eğlence olsun ya da işi uzatsın diye yazılmaz. En önemli özelliği standardizasyondur. Bu konuyu örnekleyerek devam edelim...
Örneğin aşağıdaki gibi bir sınıfımız var.
public class ToplamaIslemi
{
public int IslemYap(int x, int y)
{
return x + y;
}
}
Bu basit sınıfımızı örnek olarak hazırladığımız Console uygulamasında aşağıdaki gibi çağırıyoruz.
static void Main(string[] args)
{
ToplamaIslemi toplama = new ToplamaIslemi();
int sonuc = toplama.IslemYap(10, 20);
Console.WriteLine(sonuc.ToString());
}
Ve sonuç aşağıdaki gibi oluyor.

Bu örnekte ben sınıfın içinde IslemYap isimli bir metod olduğunu biliyordum ve doğrudan sınıf örneği üzerinden bu metodu çağırdım. Peki ya benim çağıracağım sınıfın bu metodu içerip içermediğinden emin değilsem? Yani anlatmak istediğim, modüler bir uygulama geliştirdiniz ve geliştirilen modülün çalışabilmesi için bazı metodları ve özellikleri olması gerekiyor ki sizin uygulamanız ile uyumlu çalışabilsin ama bundan nasıl emin olacaksınız ve bu metodlara nasıl erişeceksiniz.
Bu durum da interface'ler size büyük kolaylık sağlar. Örneğin şöyle bir interface hazırlayalım.
interface IMatematikselIslem<T>
{
T IslemYap(T x, T y);
}
Generic özelliğine sahip olan bir interface tanımladık, böylece istediğimiz veri türünü kullanabiliriz. Şimdi Çarpma, Çıkarma ve Bölme işlemleri için birer sınıf yazalım.
public class CarpmaIslemi : IMatematikselIslem<int>
{
public int IslemYap(int x, int y)
{
return x * y;
}
}
public class CikarmaIslemi : IMatematikselIslem<int>
{
public int IslemYap(int x, int y)
{
return x - y;
}
}
public class BolmeIslemi : IMatematikselIslem<double>
{
public double IslemYap(double x, double y)
{
if (y == 0.0)
throw new DivideByZeroException("Bir sayı sıfıra bölünemez");
else if (x == 0.0)
return 0.0;
else
return x / y;
}
}
Görüldüğü üzere generic yapısını kullanmamız bize bölme işleminde kolaylık sağladı. Tekrar Main() metoduna dönecek olursak,
static void Main(string[] args)
{
CarpmaIslemi carpmaIslemi = new CarpmaIslemi();
BolmeIslemi bolmeIslemi = new BolmeIslemi();
CikarmaIslemi cikarmaIslemi = new CikarmaIslemi();
ToplamaIslemi toplamaIslemi = new ToplamaIslemi();
List<object> islemler = new List<object>(); // işlemleri kolleksiyon halinde saklayacağız
// tek bir satırda işlemleri atmak için AddRange metodunu kullandık, object dizisini de parametre olarak yolladık.
islemler.AddRange(new object[] {carpmaIslemi, bolmeIslemi, cikarmaIslemi, toplamaIslemi});
foreach (object islem in islemler)
{
//generic tür olarak int alan işlemler
if (islem is IMatematikselIslem<int>)
{
IMatematikselIslem<int> matIslemi = (IMatematikselIslem<int>)islem;
int sonuc = matIslemi.IslemYap(10, 20);
Console.WriteLine("Islem: "+ islem.GetType() +", Sonucu:" + sonuc.ToString());
}
else if (islem is IMatematikselIslem<double>)
{
// double olarak işlem yapacaksak
IMatematikselIslem<double> matIslemi = (IMatematikselIslem<double>)islem;
double sonuc = matIslemi.IslemYap(10.0, 2.0);
Console.WriteLine("Islem: "+ islem.GetType() +", Sonucu:" + sonuc.ToString());
}
else
{
Console.WriteLine("Islem: " + islem.GetType() + " çalıştırılamaz.");
}
}
}
Görüldüğü üzere Main() metodunu baya değiştirdik, aslında yaptığımız şey basit.
- Öncelikle tüm işlemler için bir sınıf örneği oluşturduk.
- Ardından object türünden generic bir List kolleksiyonu oluşturduk ve tüm sınıf örneklerini içine AddRange metodu ile attık.
- Kolleksiyonumuz içinde foreach ile dönmeye başladık.
- Her kayıtta önce if (islem is IMatematikselIslem<int>) kontrolü yaptık. is anahtarı kelimesi bir sınıfın verilen arayüzü (interface'i) uygulayıp uygulamadığını belirlemekte kullanılır ve geriye bool değer döndürür. Burada da IMatematikselIslem arayüzünü <int> türü ile uygulayan olup olmadığını kontrol ettik ve Toplama ile Çıkarma işlemlerini bulduk.
- İşlemin uygun olduğunu tespit edince
IMatematikselIslem<int> matIslemi = (IMatematikselIslem<int>)islem;
Satırı ile nesnenin arayüze referansını verdik.
- Daha sonrada matIslemi arayüz referansı ile aşağıdaki satırı kullanarak IslemYap metodunu çağırdık.
int sonuc = matIslemi.IslemYap(10, 20);
- Sonra da elde ettiğimiz sonucu ekrana yazdık.
- Eğer kayıt <int> türünü uygulamamışsa, <double>'ı uygulamış olabilir diye kontrol ettik ve uygun olanlar için 5. , 6. ve 7. adımları uyguladık.
- Şayet bu iki kontrolde de başarısız olursa bu işlemin arayüzünü uygulamadığını anlıyoruz ve çalıştırmıyoruz.
Aklınıza şu soru gelecektir, niye? Çünkü biz burada IMatematikselIslem arayüzünü uygulamayan ToplamaIslemi sınıfının içinde IslemYap isimli bir metod olduğunu biliyoruz, ama emin miyiz? Ya yoksa, ya da şartlara uymuyorsa. Kodu kendimiz yazmadığımız durumlarda bunu daha iyi anlayabilirsiniz. Programımızı çalıştırınca aşağıdaki gibi bir çıktı oluşturacak

Gördüğünüz gibi oluşturduğumuz arayüz sayesinde, arayüz referansını kullanarak sınıf nesnemizin içinde ki metodu çalıştırdık ve arayüz uygulanmış olduğu içinde istediğimiz gibi olduğuna emin olduk.
Son olarak uygulamayı şu şekilde düzenleyelim. Uygulamanın içinde bulunan matematiksel işlem yapan sınıfların her birini ayrı bir DLL haline getirelim ve uygulamamızın bulunduğu dizinde bulunan Islemler içindeki bir klasöre atalım. Daha sonra uygulamadan burada bulunan DLL'leri uygulamaya yükleyelim ve içlerinde bulunan sınıfların metodlarını kontrol ederek çağıralım.
static void Main(string[] args)
{
// programın çalıştığı klasörü tespit edip, Moduller klasörünü ekliyoruz.
string modullerKlasorPath = AppDomain.CurrentDomain.BaseDirectory + "Moduller\\";
// Bu klasöre ulaşıyoruz
System.IO.DirectoryInfo modullerKlasoru = new System.IO.DirectoryInfo(modullerKlasorPath);
// .dll uzantılı dosyaları dolaşıyoruz
foreach (System.IO.FileInfo dosya in modullerKlasoru.GetFiles("*.dll"))
{
// elimizdeki dosyayı Assembly olarak yüklüyoruz.
System.Reflection.Assembly modul = System.Reflection.Assembly.LoadFile(dosya.FullName);
// Yüklenen assembly'nin içindeki türleri dolaşıyoruz
foreach (Type t in modul.GetTypes())
{
// elimizdeki assembly bir sınıfa mı ait yoksa başka bir türe mi (örneğin interface)
if (t.IsClass)
{
bool intKontrol = Activator.CreateInstance(t) is IMatematikselIslem<int>;
bool doubleKontrol = Activator.CreateInstance(t) is IMatematikselIslem<double>;
if (intKontrol)
{
// bu <int> türünde arayüz uygulanmış bir sınıf, çalıştıralım artık.
IMatematikselIslem<int> p = (IMatematikselIslem<int>)Activator.CreateInstance(t);
int sonuc = p.IslemYap(10, 20);
Console.WriteLine("Islem:" + t.ToString() + ", sonuç: " + sonuc.ToString());
}
else if (doubleKontrol) // double da olabilir.
{
// bu <double> türünde arayüz uygulanmış bir sınıf, çalıştıralım artık.
IMatematikselIslem<double> d = (IMatematikselIslem<double>)Activator.CreateInstance(t);
double sonuc = d.IslemYap(10.0, 2.5);
Console.WriteLine("Islem:" + t.ToString() + ", sonuç: " + sonuc.ToString());
}
else
{
Console.WriteLine(t.ToString() + " türü IMatematikselIslem arayüzünü uygulamadığı için çalıştırılamamaktadır");
}
}
}
}
}
Bu kodu da çalıştırdığımız zaman aşağıdaki gibi bir çıktı oluşuyor.

İnşallah bu sefer Interface (arayüz) kavramını açıklama şansı bulabilmişimdir. Bu uygulamada yapılan iki örneği de aşağıdaki bağlantıyı kullanarak indirebilirsiniz.
İndir
Bu yazıyı ilk değerlendiren siz olun
- Currently 0/5 Stars.
- 1
- 2
- 3
- 4
- 5
.Net Framework, C#