C# Genellikleri (Generics) Uzmanlaşma
C#'taki generics, dile eklenmesinden bu yana ayrılmaz bir parçası haline gelmiştir ve her ne kadar çalışma mantığı tüm geliştiriciler tarafından tam olarak anlaşılmasa da birçok fayda sağlamaktadır. C#'da Generics Yaratma ve Yeni Özellikler adlı videosunda, Tim Corey generics'in neden önemli olduğunu, nasıl oluşturulacağını ve pratik uygulamalarını açıklar.
Bu makale, C# generics için kapsamlı bir rehber sunmakta ve konuyla ilgili Tim Corey'nin videosundan değerli bilgiler sunmaktadır. Generics'in temellerini, tür güvenliğini, performans faydalarını ve pratik uygulamaları kapsar. Makale ayrıca generic metodlar, sınıflar, arayüzler yaratmayı ve generics'e kısıtlamalar uygulamayı keşfeder. Ek olarak, gerçek dünya kullanım alanları ve generics'i kullanarak verimli, tür güvenli kod yazmanın önemi vurgulanır.
Giriş
C# generics, geliştiricilerin herhangi bir veri tipiyle çalışan sınıfları, metodları, arayüzleri ve koleksiyonları tanımlayarak esnek, yeniden kullanılabilir ve tür güvenli kod yaratmaları için güçlü bir yol sunar. Generic bir sınıf veya metod kullanarak, geliştiriciler herhangi bir veri tipini temsil edebilecek bir generic tür parametresi (örneğin, T) tanımlayabilirler. Bu, kodun çoğaltılması gereksinimini ortadan kaldırır ve tür güvenliğini derleme sırasında sağlarken, kodun yeniden kullanılabilirliğini artırır. List ve Dictionary<TKey, TValue> gibi jenerik koleksiyon sınıfları, farklı veri türlerinin verimli bir şekilde işlenmesine olanak tanırken, jenerik arabirimler ve jenerik delege, birden çok tür parametresi ile çalışabilen özel jenerik türlerin oluşturulmasını sağlar. Generics kullanarak, geliştiriciler kod verimliliğini en üst düzeye çıkarabilir ve generic olmayan sınıfların dezavantajlarını en aza indirebilirler. Bu esneklik, performanstan veya tür güvenliğinden ödün vermeden daha fazla yeniden kullanılabilir kod oluşturulmasına olanak tanır.
Tim, (0:00)'da konuyu tanıtarak C#'da generics'in yaygın kullanımını vurgular. Generics'in neden gerektiğini açıklamayı ve onları nasıl etkili şekilde oluşturacağını ve kullanacağını göstermeyi amaçlamaktadır.
Proje Oluşturma
Tim, generics'i gösterme amacıyla tamamen konsol uygulamasına odaklanabilmek için "GenericsDemoApp" adlı yeni bir konsol uygulaması oluşturarak başlar. .NET 8 ve Visual Studio 2022'yi kullanarak projeyi kurar.
Generics'in Temelleri
Tim, genel tür kavramını açıklamak için List sınıfını kullanan bir örnekle (2:22) başlar. Generics, bir koleksiyonun tutabileceği elemanların türünü belirtmeye, tür güvenliği sağlamaya ve çalışma zamanı hatalarından kaçınılmasına olanak tanır.
List<int> numbers = new List<int> { 1, 2, 3 };
List<string> strings = new List<string> { "Tim", "Corey", "Sue" };List<int> numbers = new List<int> { 1, 2, 3 };
List<string> strings = new List<string> { "Tim", "Corey", "Sue" };List, yalnızca tamsayıların sayılar listesine ve yalnızca dizelerin dizeler listesine eklenebilmesini sağlar.
Tür Güvenliği ve Verimlilik
Tim, generics'in sağladığı tür güvenliğinin önemini vurgular. Derleyici tasarım zamanında türleri kontrol ederek, tür uyumsuzluklarını önler ve güvenli bir kod yürütülmesini sağlar. Generics ayrıca boxing ve unboxing'i engelleyerek daha verimli kod sağlar.
Genel Olmayan Koleksiyonların Verimsizliği
Genel olmayan koleksiyonları kullanmanın verimsizliğini göstermek için, Tim bir Liste yaratır ve nasıl farklı türlerde nesneler tutabileceğini gösterir.
List<object> objects = new List<object> { "Tim", 4, 3.6m };List<object> objects = new List<object> { "Tim", 4, 3.6m };Genel olmayan koleksiyonların kullanımının, tür uyumsuzluklarına ve boxing ve unboxing nedeniyle verimsizliklere yol açabileceğini açıklar.
Performans Karşılaştırması
Tim, (6:15)'te List
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
for (int i = 1; i <= 1_000_000; i++)
{
objects.Add(i);
}
stopwatch.Stop();
Console.WriteLine($"List of object elapsed time: {stopwatch.ElapsedMilliseconds} ms");
stopwatch.Restart();
for (int i = 1; i <= 1_000_000; i++)
{
numbers.Add(i);
}
stopwatch.Stop();
Console.WriteLine($"List of int elapsed time: {stopwatch.ElapsedMilliseconds} ms");Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
for (int i = 1; i <= 1_000_000; i++)
{
objects.Add(i);
}
stopwatch.Stop();
Console.WriteLine($"List of object elapsed time: {stopwatch.ElapsedMilliseconds} ms");
stopwatch.Restart();
for (int i = 1; i <= 1_000_000; i++)
{
numbers.Add(i);
}
stopwatch.Stop();
Console.WriteLine($"List of int elapsed time: {stopwatch.ElapsedMilliseconds} ms");Sonuçlar, List

Bir Tür Kontrolcüsü Metodu Oluşturma
Tim, (10:14)'te TürKontrolcüsü adında genel bir metod oluşturmayı gösterir. Bu metod, verilen bir değerin türünü kontrol edip yazdırır ve türlerin esneklik ve gücünü gösterir.
public static void TypeChecker<t>(T value)
{
Console.WriteLine($"Type: {typeof(T)}, Value: {value}");
}public static void TypeChecker<t>(T value)
{
Console.WriteLine($"Type: {typeof(T)}, Value: {value}");
}TürKontrolcüsü metodu, generic parametre T'nin türünü belirlemek için typeof operatörünü kullanır ve hem türü hem de değeri yazdırır.
Tür Kontrolcüsü Metodunu Kullanma
Tim, TürKontrolcüsü metodunu farklı türdeki argümanlarla çağırmanın örneklerini sunar.
TypeChecker(1); // Type: System.Int32, Value: 1
TypeChecker("Tim"); // Type: System.String, Value: Tim
TypeChecker(1.1); // Type: System.Double, Value: 1.1TypeChecker(1); // Type: System.Int32, Value: 1
TypeChecker("Tim"); // Type: System.String, Value: Tim
TypeChecker(1.1); // Type: System.Double, Value: 1.1TürKontrolcüsü metoduna çeşitli türler gönderen Tim, generics'in farklı veri türlerini sorunsuz bir şekilde nasıl işleyebileceğini gösterir.
Genel Bir Sınıf Oluşturma: Daha İyi Liste
Tim 16:25'te BetterList adında bir generic sınıf oluşturmaya geçiyor. Bu sınıf belirli bir türün listesini kapsar ve ek işlevsellik sağlar.
public class BetterList<t>
{
private List<t> data = new List<t>();
public void AddToList(T value)
{
data.Add(value);
Console.WriteLine($"{value} has been added to the list");
}
}public class BetterList<t>
{
private List<t> data = new List<t>();
public void AddToList(T value)
{
data.Add(value);
Console.WriteLine($"{value} has been added to the list");
}
}BetterList sınıfı, özel bir List ve listeye bir değer eklerken eklemeyi belirten bir mesaj yazdıran bir AddToList yöntemi içerir.
Better List Sınıfını Kullanma
Tim, BetterList sınıfını farklı türlerle kullanmanın örneklerini sunar.
BetterList<int> betterNumbers = new BetterList<int>();
betterNumbers.AddToList(5);
BetterList<PersonRecord> people = new BetterList<PersonRecord>();
people.AddToList(new PersonRecord("Tim", "Corey"));BetterList<int> betterNumbers = new BetterList<int>();
betterNumbers.AddToList(5);
BetterList<PersonRecord> people = new BetterList<PersonRecord>();
people.AddToList(new PersonRecord("Tim", "Corey"));Bu örneklerde BetterList
Generic Arayüz Oluşturma
Tim, 21:48'de IImportance adında bir generic arayüz fikrini tanıtıyor. Bu arayüz, iki değerden hangisinin daha önemli olduğunu belirlemek için bir yöntem tanımlar.
public interface IImportance<t>
{
T MostImportant(T a, T b);
}public interface IImportance<t>
{
T MostImportant(T a, T b);
}Generic Arayüzü Uygulama
Tim, bu arayüzü farklı türlerde nasıl uygulayabileceğini gösteriyor. Öncelikle tamsayılar için bir uygulama ile başlıyor.
public class EvaluateImportance : IImportance<int>
{
public int MostImportant(int a, int b)
{
return a > b ? a : b;
}
}public class EvaluateImportance : IImportance<int>
{
public int MostImportant(int a, int b)
{
return a > b ? a : b;
}
}Sonra, önemini belirlemek için dize uzunluğunu kullanarak dize uygulamasını gerçekleştiriyor.
public class EvaluateStringImportance : IImportance<string>
{
public string MostImportant(string a, string b)
{
return a.Length > b.Length ? a : b;
}
}public class EvaluateStringImportance : IImportance<string>
{
public string MostImportant(string a, string b)
{
return a.Length > b.Length ? a : b;
}
}Bu uygulamalar, aynı arayüzün her tür için belirli bir mantıkla farklı türlere nasıl uygulanabileceğini gösterir.
Generic'lere Kısıtlamalar Uygulama
Tim 25:21'de generiklere kısıtlamalar nasıl uygulanacağını, belirli koşulları karşılamalarını sağlayacak şekilde açıklar. Örneğin, bir generic türün boş bir yapıcıya sahip olması veya belirli bir arayüzü uygulaması kısıtlanabilir.
public class SampleClass<t> where T : new()
{
// Class implementation
}
public class SampleClassWithInterface<t> where T : IImportance<t>
{
// Class implementation
}public class SampleClass<t> where T : new()
{
// Class implementation
}
public class SampleClassWithInterface<t> where T : IImportance<t>
{
// Class implementation
}Bu kısıtlamalar, generic tipin gerekli kriterleri karşılamasını sağlamaya yardımcı olur, çalışma zamanı hatalarını önler ve tür güvenliğini artırır.
Microsoft'un INumber Uygulaması
Tim, Microsoft'un sayısal işlemleri kısıtlamak için INumber arayüzünü nasıl kullandığını tartışıyor. Bu, generic türler üzerinde toplama ve çıkarma gibi aritmetik işlemlere izin verir.
public class MathOperations<t> where T : INumber<t>
{
public T Add(T x, T y)
{
return x + y;
}
}public class MathOperations<t> where T : INumber<t>
{
public T Add(T x, T y)
{
return x + y;
}
}Genel tür T'yi INumber ile kısıtlayarak, türün sayısal işlemleri desteklediğini garanti eder.
Farklı Sayısal Türlerle Generikleri Kullanma
Tim 33:55'te MathOperations sınıfını genişleterek, generiklerin çift ve ondalık gibi farklı sayısal türler ile nasıl kullanılabileceğini gösterir.
Tim, tamsayılar ve çiftler için MathOperations örneklerinin nasıl oluşturulacağını gösterir:
MathOperations<int> intMath = new MathOperations<int>();
Console.WriteLine(intMath.Add(1, 4)); // Outputs: 5
MathOperations<double> doubleMath = new MathOperations<double>();
Console.WriteLine(doubleMath.Add(1.5, 4.3)); // Outputs: 5.8MathOperations<int> intMath = new MathOperations<int>();
Console.WriteLine(intMath.Add(1, 4)); // Outputs: 5
MathOperations<double> doubleMath = new MathOperations<double>();
Console.WriteLine(doubleMath.Add(1.5, 4.3)); // Outputs: 5.8Bu, generiklerin esnekliğini, farklı sayısal türleri aynı sınıfta sorunsuz bir şekilde ele alabilme yeteneğini gösterir.
Farklı Sayısal Türleri Ele Alma
Tim, tür güvenliğinin önemine değinir ve farklı sayısal türlerin karıştırılamayacağını gösterir. Örneğin, bir çift ve tamsayıyı toplama girişimi derleme zamanı hatasına neden olur.
// This will result in a compile-time error
// Console.WriteLine(intMath.Add(1.5, 4));// This will result in a compile-time error
// Console.WriteLine(intMath.Add(1.5, 4));Tür Dönüşüm Yükünü Önleme
Tim, tür dönüşümü ile ilişkilendirilen yükten kaçınmak için generiklerin kullanımının avantajlarını açıklar. Örneğin, tamsayıları matematiksel işlemler için çiftlere dönüştürmek ve sonra tekrar tamsayılara dönüştürmek maliyetli olabilir. Generikler kullanarak, yerel türler üzerinde doğrudan işlemler yapılabilir, performans ve hassasiyet korunur.
Pratikte Generikler
Tim, generiklerin kullanımı konusunda dikkatli olmayı önerir, geliştiricilere onları uygun şekilde kullanmalarını ve aşırı kullanımından kaçınmalarını tavsiye eder. Generiklerin tür güvenliği, boxing ve unboxing azaltılması, derleme zamanı denetimi ve kod okunabilirliğinin artırılması gibi faydalarına vurgu yapar.
Generics'in, List ve Dictionary<TKey, TValue> gibi koleksiyonlarda yaygın olduğuna ve belirli ayrıntıları önceden bilmeden çeşitli türleri işleme gereken günlük çerçevelerde de kullanıldığına dikkat çeker.
Sonuç
Tim Corey'nin C#'ta ileri seviye generiklerle ilgili detaylı keşfi pratik uygulamalar ve faydalı kavrayışlar sağlar. Generikleri daha iyi anlamak ve gerçek dünyadaki örnekleri aksiyon halinde görmek istiyorsanız, Tim Corey'nin C# Generics hakkındaki detaylı videosunu izlemeyi unutmayın. Açık açıklamaları ve uygulamalı gösterimleri, kavramları tam olarak kavramanızı ve kendi projelerinizde etkili bir şekilde uygulamanızı sağlayacaktır.

