C#

C# dilinde Dependency Injection ve Katmanlı Mimari

Dependency Injection (Bağımlılık Enjeksiyonu) ve Katmanlı Mimari, modern C# uygulamalarının temel yapı taşlarıdır. Bu yapılar, yazılımın sürdürülebilirliğini, test edilebilirliğini ve esnekliğini artırır. Doğru bir şekilde kullanıldığında, uygulama geliştirme sürecini kolaylaştırır ve kodun daha anlaşılır olmasını sağlar.

Dependency Injection Nedir?

Dependency Injection, bir sınıfın ihtiyaç duyduğu bağımlılıkların dışarıdan enjekte edilmesi prensibine dayanır. Bu sayede sınıflar arası bağımlılıklar azaltılır, kodun test edilebilirliği ve esnekliği artar. C# ve .NET ecosystem’inde DI, yerleşik olarak desteklenen bir özelliktir. IServiceCollection ve IServiceProvider gibi yapılar ile uygulamaya entegre edilir.

Katmanlı Mimari Nedir?

Katmanlı mimari, yazılım uygulamalarını mantıksal katmanlara ayırarak daha düzenli ve sürdürülebilir bir yapı kurmayı amaçlar. Genellikle bu katmanlar şunlardır:

  • Presentation Katmanı: Kullanıcı arayüzü ve istemci tarafı işlemlerini yönetir.
  • Business Katmanı: Uygulamanın iş kurallarını ve süreçlerini içerir.
  • Data Access Katmanı: Veritabanı veya diğer veri kaynaklarıyla olan iletişimi sağlar.

Bu katmanlar, birbirinden bağımsız olarak geliştirilebilir ve test edilebilir. Katmanlar arası iletişim, genellikle interface’ler aracılığıyla sağlanır.

Dependency Injection ile Katmanlı Mimarinin Entegrasyonu

C# uygulamalarında DI, katmanlı mimarinin uygulanmasında kritik bir rol oynar. Her katman kendi bağımlılıklarını dışarıdan alır. Örneğin, Business katmanı, Data Access katmanındaki bir servise ihtiyaç duyduğunda bu servis DI ile enjekte edilir. Bu yapı, kodun daha test edilebilir ve bakımı kolay bir hale gelmesini sağlar.

Örnek Uygulama Yapısı

Aşağıda basit bir örnek üzerinden ilerleyelim:

// Data Access Katmanı
public interface IUserRepository
{
    User GetUserById(int id);
}

public class UserRepository : IUserRepository
{
    public User GetUserById(int id)
    {
        // Veritabanı işlemleri
        return new User { Id = id, Name = "Ahmet" };
    }
}

// Business Katmanı
public interface IUserService
{
    User GetUser(int id);
}

public class UserService : IUserService
{
    private readonly IUserRepository _userRepository;

    public UserService(IUserRepository userRepository)
    {
        _userRepository = userRepository;
    }

    public User GetUser(int id)
    {
        return _userRepository.GetUserById(id);
    }
}

// Presentation Katmanı (örneğin bir ASP.NET Core Controller)
[ApiController]
[Route("[controller]")]
public class UsersController : ControllerBase
{
    private readonly IUserService _userService;

    public UsersController(IUserService userService)
    {
        _userService = userService;
    }

    [HttpGet("{id}")]
    public IActionResult GetUser(int id)
    {
        var user = _userService.GetUser(id);
        return Ok(user);
    }
}

Dependency Injection Yapılandırması

Bu yapıyı ASP.NET Core uygulamasında kullanmak için aşağıdaki gibi bir yapılandırma yapılır:

// Program.cs veya Startup.cs içinde
builder.Services.AddScoped<IUserRepository, UserRepository>();
builder.Services.AddScoped<IUserService, UserService>();

Bu sayede, her katman kendi bağımlılıklarını dışarıdan alır. Sisteme yeni bir veri kaynağı entegre edilmek istendiğinde, sadece repository katmanı değişir, diğer katmanlarda bir değişiklik gerekmez.

Dependency Injection Türleri

DI, genellikle üç şekilde uygulanır:

  • Constructor Injection: Bağımlılıklar sınıfın constructor’ı üzerinden enjekte edilir. Bu yöntem en yaygın ve önerilen yöntemdir.
  • Property Injection: Bağımlılıklar sınıfın property’lerine atanır. Genellikle opsiyonel bağımlılıklar için kullanılır.
  • Method Injection: Bağımlılıklar sınıfın metotlarına parametre olarak geçirilir. Daha az yaygın bir yöntemdir.

Test Edilebilirlik ve Dependency Injection

Dependency Injection, unit test yazmayı kolaylaştırır. Örneğin, IUserService için bir test yazarken, IUserRepository interface’ini taklit eden bir mock nesne kullanılabilir:

[Fact]
public void GetUser_Should_Return_User()
{
    // Arrange
    var mockRepo = new Mock<IUserRepository>();
    mockRepo.Setup(r => r.GetUserById(1)).Returns(new User { Id = 1, Name = "Ahmet" });

    var userService = new UserService(mockRepo.Object);

    // Act
    var result = userService.GetUser(1);

    // Assert
    Assert.NotNull(result);
    Assert.Equal("Ahmet", result.Name);
}

Katmanlı Mimari Avantajları

Katmanlı mimarinin sağladığı başlıca avantajlar şunlardır:

  • Modülerlik: Katmanlar birbirinden bağımsızdır, bu da geliştirme sürecini kolaylaştırır.
  • Bakım Kolaylığı: Bir katmanda yapılan değişiklik, diğer katmanları etkilemez.
  • Yeniden Kullanılabilirlik: Aynı katmanlar farklı projelerde de kullanılabilir.
  • Test Edilebilirlik: Her katman ayrı ayrı test edilebilir.

Sonuç

C# dilinde Dependency Injection ve Katmanlı Mimari, uygulama geliştirme sürecinde esneklik, test edilebilirlik ve sürdürülebilirlik sağlar. Bu yapılar sayesinde kod daha temiz, daha anlaşılır ve daha yönetilebilir hale gelir. Modern .NET uygulamalarında bu iki yaklaşımın birlikte kullanılması, yazılım kalitesini ciddi anlamda artırır.


C# dilinde Asenkron ve Paralel Programlama

C# dilinde asenkron ve paralel programlama, modern uygulamaların performansını artırırken kullanıcı deneyimini de iyileştirmek için kullanılan kritik tekniklerdir. Özellikle I/O işlemlerinin yoğun olduğu veya çoklu işlemci mimarisinden faydalanmak istenen uygulamalarda bu yaklaşımlar büyük önem taşır. Bu makalede, C# dilinde asenkron programlama ile paralel programlama arasındaki farklar, kullanımı ve avantajları detaylı olarak ele alınacaktır.

Asenkron Programlama Nedir?

Asenkron programlama, bir işlemin tamamlanmasını beklemeden diğer işlemlerin devam edebilmesini sağlayan bir programlama modelidir. C# dilinde bu model genellikle async ve await anahtar kelimeleri ile uygulanır. Özellikle ağ istekleri, dosya okuma/yazma gibi I/O işlemleri sırasında uygulamanın donmasını engellemek için kullanılır.

Asenkron programlama, tek bir iş parçacığı (thread) üzerinde bile çalışabilir. Temel amacı, mevcut thread’i bloke etmeden uzun süren işlemleri başlatıp başka işlerin yapılmasına olanak tanımaktır. Uzun süren işlem tamamlandığında, bekleyen kod bloğu tekrar çalıştırılır.

Basit Bir Asenkron Metot Örneği

public async Task<string> GetDataFromWebAsync()
{
    using (HttpClient client = new HttpClient())
    {
        string result = await client.GetStringAsync("https://api.example.com/data");
        return result;
    }
}

Bu örnekte, GetStringAsync metodu çağrılırken thread bloke edilmez. Bunun yerine, işlem tamamlandığında devam edilir. Böylece kullanıcı arayüzü veya başka işlemler aksamadan devam edebilir.

Paralel Programlama Nedir?

Paralel programlama, aynı anda birden fazla işlemi gerçekleştirmek amacıyla birden fazla iş parçacığını (thread) kullanma yöntemidir. C# dilinde paralel programlama genellikle System.Threading.Tasks.Parallel sınıfı veya Task sınıfı ile yapılır. Bu yöntem, CPU yoğun işlemleri hızlandırmak için idealdir.

Paralel programlama, özellikle çok çekirdekli işlemcilerde verimli çalışır. Aynı görevin parçaları farklı çekirdeklere dağıtılarak işlem süresi kısaltılabilir. Ancak, paralel programlamada dikkat edilmesi gereken senkronizasyon ve yarış koşulları (race condition) gibi konular vardır.

Paralel.For Örneği

Parallel.For(0, 1000, i =>
{
    // Her bir i değeri için farklı bir thread çalıştırılır
    ProcessData(i);
});

Bu örnekte, 0 ile 1000 arasındaki sayılar için ProcessData metodu paralel olarak çalıştırılır. CPU’nun birden fazla çekirdeği varsa bu işlem çok daha hızlı tamamlanır.

Asenkron ve Paralel Programlama Arasındaki Farklar

Asenkron programlama ile paralel programlama karıştırılmamalıdır. Asenkron programlama, işlemciyi daha verimli kullanmak ve kullanıcı deneyimini artırmak içindir. Paralel programlama ise birden fazla işlemi aynı anda yaparak performans artışı sağlamayı amaçlar. Asenkron işlemler genellikle I/O işlemlerini içerirken, paralel işlemler CPU yoğunlukludur.

  • Asenkron programlama: Blokajı önler, genellikle tek thread’te çalışır, I/O işlemleri için uygundur.
  • Paralel programlama: Gerçek zamanlı çoklu işlem yapar, birden fazla thread kullanır, CPU yoğun işlemler için uygundur.

CancellationToken ile Asenkron İşlemleri Yönetmek

Asenkron işlemleri iptal edebilmek için C#’ta CancellationToken kullanılır. Bu token, uzun süren işlemleri kullanıcı isteğiyle veya belirli bir koşulda durdurmak için kritik öneme sahiptir.

public async Task LongRunningTask(CancellationToken token)
{
    for (int i = 0; i < 1000; i++)
    {
        token.ThrowIfCancellationRequested();
        await Task.Delay(1000, token);
        Console.WriteLine($"İşlem {i} tamamlandı.");
    }
}

Bu örnekte, ThrowIfCancellationRequested() metodu ile işlem iptal edilmişse bir istisna fırlatılır ve işlem durdurulur.

Task Sınıfı ile Paralel İşlemler

Task sınıfı, hem asenkron hem paralel işlemleri yönetmek için kullanılır. C#'ta Task.Run veya Task.Factory.StartNew ile yeni bir thread başlatılabilir ve paralel işlem yapılabilir.

Task task1 = Task.Run(() => ProcessData(1));
Task task2 = Task.Run(() => ProcessData(2));

await Task.WhenAll(task1, task2);

Bu örnekte iki farklı ProcessData işlemi ayrı thread’lerde başlatılmış ve tamamlanmaları beklenmiştir. Task.WhenAll kullanarak tüm task’lerin bitmesi beklenebilir.

Paralel LINQ (PLINQ)

PLINQ, LINQ sorgularının paralel olarak çalıştırılmasını sağlar. AsParallel() metodu ile veri koleksiyonu paralel işlenebilir.

var result = data.AsParallel()
                 .Where(x => x > 100)
                 .Select(x => x * x)
                 .ToList();

Bu örnekte, data koleksiyonu üzerindeki filtreleme ve seçim işlemleri paralel olarak yapılır. Özellikle büyük veri kümeleri üzerinde bu yöntem performans kazancı sağlar.

Senkronizasyon ve Paylaşılan Kaynaklar

Paralel programlamada birden fazla thread aynı veriye erişmeye çalıştığında senkronizasyon gerekir. C#’ta bu senkronizasyonu sağlamak için lock, Monitor, Semaphore, ReaderWriterLock gibi yapılar kullanılabilir.

private static readonly object lockObject = new object();

lock (lockObject)
{
    // Paylaşılan kaynağa erişim
    sharedResource++;
}

Bu örnekte, sharedResource değişkenine erişim lock bloğu ile senkronize edilmiştir. Böylece aynı anda yalnızca bir thread bu kaynağa erişebilir.

Async/Await ile Performans ve Kullanılabilirlik

async/await, özellikle UI tabanlı uygulamalarda kullanıcı arayüzünün donmasını engeller. Uzun süren bir işlem sırasında UI thread’in bloke edilmemesi sağlanır. Aşağıdaki örnek bir Windows Forms uygulamasında kullanımını göstermektedir:

private async void button1_Click(object sender, EventArgs e)
{
    string data = await GetDataFromWebAsync();
    label1.Text = data;
}

Bu örnek, butona tıklanıldığında veriyi arka planda asenkron olarak alırken, arayüzün donmasını engeller.

Sonuç

C# dilinde asenkron ve paralel programlama teknikleri, uygulamaların daha verimli ve kullanıcı dostu çalışmasını sağlar. Asenkron programlama I/O işlemlerinde thread blokajını önlerken, paralel programlama CPU yoğun görevlerde performans kazandırır. Doğru kullanıldığında bu teknikler, modern yazılım geliştirme süreçlerinde vazgeçilmez hale gelir. Geliştiricilerin ihtiyaçlarına göre doğru yaklaşımı seçmeleri ve uygulamalarında etkili bir şekilde kullanmaları gerekir.


C# Dilinde Csv/Excel Rapor Üretimi Ile Veri Analizi

C# programlama dili, veri işleme ve raporlama işlemleri için güçlü bir platform sunar. Özellikle CSV ve Excel formatlarında rapor üretimi yaparak veri analizi süreçlerini otomatikleştirmek mümkündür. Bu makalede, C# ile nasıl veri analizi yapılacağı, CSV ve Excel dosyalarının nasıl oluşturulacağı ve yönetileceği detaylı olarak ele alınacaktır.

C# ile Veri Analizi Nedir?

Veri analizi, büyük veri kümelerinden anlamlı bilgiler çıkarma sürecidir. C# gibi güçlü bir programlama dili sayesinde bu verileri filtreleyebilir, gruplayabilir, istatistiksel hesaplamalar yapabilir ve sonuçları görselleştirebilirsiniz. Özellikle iş zekâsı (business intelligence) projelerinde, verilerin işlenip rapor haline getirilmesi kritik bir öneme sahiptir.

C# ile veri analizi yaparken genellikle System.Data, System.Linq ve System.IO gibi namespace’lerden yararlanılır. Bu namespace’ler sayesinde verileri okuyabilir, analiz edebilir ve ardından CSV veya Excel formatında raporlayabilirsiniz.

CSV Dosyaları ile Rapor Üretimi

CSV (Comma-Separated Values) dosyaları, verilerin virgülle ayrılmış şekilde saklandığı basit bir metin dosyasıdır. C# ile CSV dosyaları oluşturmak oldukça kolaydır ve küçük veri setleri için idealdir. Aşağıda basit bir CSV dosyası oluşturma örneği verilmiştir:

using System;
using System.IO;
using System.Collections.Generic;

class CsvReporter
{
    static void Main()
    {
        var veriler = new List<string[]>
        {
            new string[] { "Ad", "Soyad", "Departman" },
            new string[] { "Ahmet", "Yılmaz", "IT" },
            new string[] { "Mehmet", "Kaya", "Pazarlama" }
        };

        using (var writer = new StreamWriter("rapor.csv"))
        {
            foreach (var satir in veriler)
            {
                writer.WriteLine(string.Join(",", satir));
            }
        }
    }
}

Bu örnekte, çalışan bilgileri bir liste halinde tutulmuş ve bu liste CSV formatında bir dosyaya yazılmıştır. StreamWriter sınıfı kullanılarak metin dosyasına yazma işlemi gerçekleştirilmiştir. string.Join metodu ile her satırdaki veriler virgülle birleştirilerek CSV formatına uygun hale getirilmiştir.

Excel Dosyaları ile Rapor Üretimi

Excel dosyaları, CSV dosyalarına göre daha zengin içerik sunar; hücre biçimlendirme, formüller, grafikler gibi özellikler içerir. C# ile Excel dosyaları oluşturmak için genellikle üçüncü taraf kütüphaneler kullanılır. En popülerlerinden biri EPPlus‘tır. NuGet Package Manager üzerinden EPPlus kütüphanesini projenize ekleyebilirsiniz.

EPPlus kütüphanesi ile Excel dosyası oluşturma örneği:

using OfficeOpenXml;
using System.IO;

class ExcelReporter
{
    static void Main()
    {
        ExcelPackage.LicenseContext = LicenseContext.NonCommercial;

        var dosya = new FileInfo("rapor.xlsx");
        using (var paket = new ExcelPackage(dosya))
        {
            var calismaSayfasi = paket.Workbook.Worksheets.Add("Çalışanlar");

            calismaSayfasi.Cells["A1"].Value = "Ad";
            calismaSayfasi.Cells["B1"].Value = "Soyad";
            calismaSayfasi.Cells["C1"].Value = "Departman";

            calismaSayfasi.Cells["A2"].Value = "Ahmet";
            calismaSayfasi.Cells["B2"].Value = "Yılmaz";
            calismaSayfasi.Cells["C2"].Value = "IT";

            calismaSayfasi.Cells["A3"].Value = "Mehmet";
            calismaSayfasi.Cells["B3"].Value = "Kaya";
            calismaSayfasi.Cells["C3"].Value = "Pazarlama";

            paket.Save();
        }
    }
}

Yukarıdaki örnekte, ExcelPackage sınıfı ile yeni bir Excel dosyası oluşturulmuş ve içine veriler yazılmıştır. LicenseContext ayarı, EPPlus’ın ücretsiz kullanım şartlarına göre düzenlenmiştir. Hücrelere doğrudan veri yazmak yerine, ihtiyaç duyulursa hücre biçimlendirme, tablo oluşturma veya grafik ekleme gibi işlemler de yapılabilir.

C# ile Veri Analizi Süreci

C# ile veri analizi yaparken genellikle LINQ (Language Integrated Query) sorgularından yararlanılır. LINQ sayesinde veri setleri üzerinde filtreleme, sıralama, gruplama ve toplama işlemleri kolaylıkla yapılabilir. Aşağıda basit bir LINQ sorgusu örneği verilmiştir:

using System;
using System.Collections.Generic;
using System.Linq;

class Veri
{
    public string Ad { get; set; }
    public string Departman { get; set; }
    public decimal Maas { get; set; }
}

class Program
{
    static void Main()
    {
        var calisanlar = new List<Veri>
        {
            new Veri { Ad = "Ahmet", Departman = "IT", Maas = 10000 },
            new Veri { Ad = "Mehmet", Departman = "Pazarlama", Maas = 8000 },
            new Veri { Ad = "Ayşe", Departman = "IT", Maas = 12000 }
        };

        var analizSonucu = calisanlar
            .Where(c => c.Departman == "IT")
            .Select(c => new { c.Ad, c.Maas })
            .ToList();

        foreach (var sonuc in analizSonucu)
        {
            Console.WriteLine($"{sonuc.Ad} - {sonuc.Maas}");
        }
    }
}

Bu örnekte “IT” departmanında çalışanlar filtrelenmiş ve ad ile maaş bilgileri yeni bir yapıda listelenmiştir. Bu tür analizler yapıldıktan sonra sonuçlar CSV veya Excel formatında raporlanabilir.

Raporlama Sürecinde Dikkat Edilmesi Gerekenler

Raporlama yapılırken verilerin doğru biçimde işlenmesi ve kullanıcı dostu hale getirilmesi gerekir. CSV ve Excel dosyalarında:

  • Verilerin doğru sıralanması,
  • Hücrelerin uygun biçimlendirilmesi,
  • Büyük veri setlerinin bellek yönetimi,
  • Kodun okunabilir ve sürdürülebilir olması,
  • Hata yönetimi ve istisna durumlarının ele alınması

gibi konular önemlidir. Özellikle Excel raporlarında hücre stilleri, tablo başlıkları ve formüller gibi görsel öğeler raporun kalitesini artırır.

Sonuç

C# ile CSV ve Excel rapor üretimi, veri analizi süreçlerini otomatikleştirmek için etkili bir yöntemdir. LINQ sorguları sayesinde veriler kolayca işlenebilir ve sonuçlar kullanıcı dostu formatlarda raporlanabilir. Bu süreçte EPPlus gibi kütüphaneler kullanılarak daha gelişmiş Excel raporları oluşturulabilir. Doğru implementasyonla veri analizi işlemleriniz daha hızlı ve güvenilir hale gelir.


C# Dilinde Kişisel Bütçe Yönetim Uygulaması

C# programlama dili kullanılarak geliştirilen kişisel bütçe yönetim uygulamaları, bireylerin gelir ve giderlerini düzenli olarak takip etmelerine yardımcı olan güçlü yazılım çözümleridir. Bu tür uygulamalar, kullanıcıların finansal hedeflerine ulaşmalarını kolaylaştırırken aynı zamanda harcamalarını kontrol altında tutmalarını sağlar. C#’ın nesne yönelimli yapısı ve zengin kütüphane desteği sayesinde geliştirilen bu uygulamalar, kullanıcı dostu arayüzlerle birlikte veri güvenliği ve verimlilik açısından da oldukça güçlüdür.

Kişisel Bütçe Yönetim Uygulaması Nedir?

Kişisel bütçe yönetim uygulaması, bireylerin gelir ve giderlerini kaydederek finansal durumlarını analiz etmelerini sağlayan bir yazılım türüdür. Bu uygulamalar genellikle gelir kaynakları, sabit ve değişken giderler, tasarruflar ve borçlar gibi verileri yönetmek için kullanılır. Kullanıcılar, bu verileri kategorilere ayırarak aylık, yıllık veya özel dönemlerde harcama analizleri yapabilir. C# dilinde geliştirilen bu tür uygulamalar, masaüstü veya web tabanlı olarak çalışabilir. Ayrıca verilerin güvenli bir şekilde saklanması ve raporlama gibi özellikler sunulabilir.

Neden C# Kullanılır?

C#, Microsoft tarafından geliştirilen ve özellikle Windows platformunda güçlü bir performans gösteren nesne yönelimli bir programlama dilidir. C# ile geliştirilen uygulamalar, .NET Framework veya .NET Core gibi güçlü platformlar üzerinde çalışabilir. Bu nedenle, güvenli, hızlı ve ölçeklenebilir bir kişisel bütçe yönetim uygulaması oluşturmak için idealdir. Ayrıca C#’ın Windows Forms veya WPF gibi grafiksel arayüz tasarım araçlarıyla uyumu sayesinde kullanıcı dostu uygulamalar kolayca geliştirilebilir. Veritabanı işlemleri için Entity Framework gibi ORM (Object Relational Mapping) araçlarıyla entegrasyon da kolaydır.

Temel Özellikler

Bir kişisel bütçe yönetim uygulamasının sahip olması gereken temel özellikler şunlardır:

  • Gelir ve Gider Kayıtları: Kullanıcılar sabit maaşları, ek gelirleri ve tüm giderlerini sisteme kaydedebilir.
  • Kategori Yönetimi: Giderler, kategorilere (örneğin: ev, ulaşım, eğlence) ayrılabilir.
  • Raporlama ve Görselleştirme: Harcamaların grafiksel veya tablolu raporları sunularak analiz kolaylaştırılır.
  • Bütçe Planlama: Kullanıcılar belirli kategoriler için bütçe limiti belirleyebilir ve harcamalarını bu limite göre takip edebilir.
  • Veri Güvenliği: Kullanıcı bilgileri şifrelenerek saklanmalı ve erişim kontrollü olmalıdır.

Uygulama Mimarisi

C# ile bir kişisel bütçe yönetim uygulaması geliştirirken genellikle üç katmanlı mimari (3-tier architecture) kullanılır. Bu mimari, uygulamanın daha düzenli, bakımı kolay ve test edilebilir olmasını sağlar:

  1. Sunum Katmanı (Presentation Layer): Kullanıcı arayüzüdür. Windows Forms veya WPF kullanılarak tasarlanabilir.
  2. İş Katmanı (Business Logic Layer): Uygulamanın temel iş kurallarını ve işlemlerini içerir. Örneğin gelir/gider ekleme, kategori atama gibi işlemler burada yapılır.
  3. Veri Katmanı (Data Access Layer): Veritabanı ile iletişim burada sağlanır. Entity Framework veya ADO.NET kullanılarak veri kaydedilir, güncellenir veya silinir.

Veritabanı Tasarımı

Uygulamanın veritabanı tasarımı, bütçeleme işleminin başarısı açısından kritik öneme sahiptir. Örnek veritabanı tabloları şu şekilde olabilir:

  • Kullanıcılar (Users): Kullanıcı kimlik bilgileri, şifre, kayıt tarihi.
  • Gelirler (Incomes): Gelir miktarı, türü, açıklaması, tarihi.
  • Giderler (Expenses): Gider miktarı, kategorisi, tarihi, açıklaması.
  • Kategoriler (Categories): Gider kategorileri (Ev, Ulaşım, Eğitim vb.).
  • Bütçeler (Budgets): Her kategori için belirlenen bütçe limitleri ve dönem bilgileri.

Veritabanı olarak genellikle Microsoft SQL Server, SQLite veya MySQL tercih edilir. C# uygulaması, bu veritabanlarıyla Entity Framework veya direkt SQL sorguları aracılığıyla entegre çalışabilir.

Kullanıcı Arayüzü Tasarımı

Kullanıcı arayüzü (UI), uygulamanın en önemli bileşenlerinden biridir. Kullanıcıların kolayca işlem yapabilmesi için sade ve anlaşılır bir arayüz gereklidir. C# ile geliştirilen kişisel bütçe uygulamalarında genellikle Windows Forms veya WPF tercih edilir. Örneğin:

  • Ana sayfada toplam gelir/gider bilgisi ve kalan bütçe miktarı gösterilebilir.
  • Ayrı bir pencere üzerinden gelir ve gider ekleme/silme işlemleri yapılabilir.
  • Grafiksel raporlar için Chart kontrolü kullanılabilir.

Örnek Kod Parçası

Aşağıda C# ile yazılmış basit bir gelir ekleme fonksiyonu örneği verilmiştir:


public void AddIncome(decimal amount, string description, DateTime date)
{
    using (var context = new BudgetContext())
    {
        var income = new Income
        {
            Amount = amount,
            Description = description,
            Date = date
        };
        context.Incomes.Add(income);
        context.SaveChanges();
    }
}

Bu fonksiyon, Entity Framework kullanılarak veritabanına yeni bir gelir kaydı ekler. Benzer şekilde gider ekleme, kategori atama ve raporlama işlemleri de geliştirilebilir.

Güvenlik Önlemleri

Kişisel bütçe uygulamaları hassas finansal veriler içerdiğinden, güvenlik en önemli konulardan biridir. C# ile geliştirilen bu uygulamalarda şu güvenlik önlemleri alınabilir:

  • Kullanıcı şifreleri bcrypt veya benzeri algoritmalarla şifrelenerek saklanmalıdır.
  • Veritabanı erişimleri için kullanıcı adı ve şifre gibi bilgiler app.config veya secrets.json dosyalarında güvenli şekilde saklanmalı.
  • Yetkisiz erişimleri engellemek için kullanıcı girişi (login) kontrolü yapılmalıdır.
  • Verilerin yedeklenmesi ve geri yüklenmesi özelliği eklenmelidir.

Sonuç

C# ile geliştirilen kişisel bütçe yönetim uygulamaları, kullanıcıların finansal durumlarını daha iyi anlamalarına ve planlamalarına yardımcı olan güçlü araçlardır. Doğru mimari, veritabanı tasarımı ve kullanıcı arayüzü ile bu tür uygulamalar oldukça etkili hale gelir. C#’ın sunduğu güvenlik ve verimlilik özellikleri sayesinde uygulamalar hem kullanıcı dostu hem de güvenli olabilir. Bu nedenle finansal disiplin kurmak isteyenler için C# ile yazılmış kişisel bütçe uygulamaları ideal bir çözümdür.


C# Dilinde Basit Bir Stok Takip Sistemi Geliştirme

C# dili, nesne yönelimli programlama yapısı ve .NET framework ile birlikte veri yönetimi projelerinde oldukça güçlüdür. Bu makalede, C# kullanarak basit bir stok takip sistemi nasıl geliştirilir, adım adım ele alınacak. Sistemin temel bileşenleri, veri yapıları ve kullanıcı arayüzü oluşturma süreci detaylıca açıklanacaktır.

Stok Takip Sisteminin Temel Yapısı

Bir stok takip sisteminin temel amacı, ürün bilgilerini kaydetmek, güncellemek, sorgulamak ve gerektiğinde silmek. C# ile bu işlemi yapmak için önce ürün sınıfı tanımlanması gerekir. Ürün sınıfı, ürünün adı, kodu, miktarı ve fiyatı gibi bilgileri barındırmalıdır. Ayrıca bu sınıfa ait metotlar ile ürün ekleme, güncelleme ve silme işlemleri tanımlanabilir.

public class Urun
{
    public int Id { get; set; }
    public string Ad { get; set; }
    public int Miktar { get; set; }
    public decimal Fiyat { get; set; }

    public Urun(int id, string ad, int miktar, decimal fiyat)
    {
        Id = id;
        Ad = ad;
        Miktar = miktar;
        Fiyat = fiyat;
    }
}

Stok Verilerinin Saklanması

Bu sistemde ürün verileri bir koleksiyon yapısında tutulabilir. C#’da bu işlem için List<Urun> kullanmak uygundur. List, dinamik bir yapı sunar ve ürün ekleme, çıkarma gibi işlemler için idealdir. Aşağıdaki gibi bir stok listesi oluşturulabilir:

List<Urun> stokListesi = new List<Urun>();

Bu liste, programın tüm yaşam döngüsü boyunca ürün bilgilerini tutar. Ancak uygulama kapatıldığında veriler kaybolur. Kalıcı veri saklama için dosya işlemleri veya veritabanı entegrasyonu gerekebilir. Basit bir sistem için JSON formatında dosyaya yazma işlemleri tercih edilebilir.

Ürün Ekleme ve Yönetme İşlemleri

Stok sistemine ürün ekleme işlemi, kullanıcıdan alınan bilgilerle yeni bir ürün nesnesi oluşturarak gerçekleştirilir. Bu nesne daha sonra listeye eklenir. Örneğin yeni bir ürün eklemek için aşağıdaki metot kullanılabilir:

public void UrunEkle(Urun urun)
{
    stokListesi.Add(urun);
}

Güncelleme işlemi ise ürünün Id bilgisi üzerinden yapılır. Kullanıcı mevcut ürünü bulup miktar veya fiyat gibi alanları değiştirebilir. Silme işlemi de benzer şekilde Id’ye göre yapılır ve listeden ilgili ürün çıkarılır.

Konsol Uygulaması ile Basit Bir Arayüz

Kullanıcı ile etkileşimi sağlamak için konsol uygulaması yeterli olabilir. Kullanıcıya menü sunularak, ürün ekleme, listeleme, güncelleme ve silme işlemleri seçenek olarak verilir. Kullanıcı seçimine göre ilgili metotlar çağrılır. Örneğin:

Console.WriteLine("1. Ürün Ekle");
Console.WriteLine("2. Ürünleri Listele");
Console.WriteLine("3. Ürün Güncelle");
Console.WriteLine("4. Ürün Sil");
Console.Write("Seçiminiz: ");
int secim = Convert.ToInt32(Console.ReadLine());

Bu tür bir yapı sayesinde kullanıcı sistemi rahatlıkla kullanabilir. Daha gelişmiş bir sistem için Windows Forms veya WPF gibi grafiksel arayüzler tercih edilebilir.

Stok Azaltma ve Uyarı Mekanizması

Bir stok takip sisteminde ürün miktarının azalması da önemli bir işlemdir. Bu işlem genellikle satış veya ürün çıkarma durumlarında yapılır. Miktar azaltıldığında belirli bir seviyenin altına düşmesi durumunda kullanıcıya uyarı verilmesi sağlanabilir. Örneğin:

public void StokAzalt(int urunId, int adet)
{
    Urun urun = stokListesi.FirstOrDefault(u => u.Id == urunId);
    if (urun != null)
    {
        urun.Miktar -= adet;
        if (urun.Miktar <= 5)
        {
            Console.WriteLine($"{urun.Ad} için stok azaldı! Mevcut miktar: {urun.Miktar}");
        }
    }
}

Dosyaya Veri Kaydetme ve Yükleme

Program kapatıldığında verilerin kaybolmaması için ürün listesini bir dosyaya kaydetmek gerekir. C# ile JSON formatında dosyaya yazma işlemi Newtonsoft.Json kütüphanesi ile kolaylıkla yapılabilir. Aşağıda basit bir kaydetme ve yükleme örneği verilmiştir:

public void StokKaydet(string dosyaYolu)
{
    string json = JsonConvert.SerializeObject(stokListesi, Formatting.Indented);
    File.WriteAllText(dosyaYolu, json);
}

public void StokYukle(string dosyaYolu)
{
    if (File.Exists(dosyaYolu))
    {
        string json = File.ReadAllText(dosyaYolu);
        stokListesi = JsonConvert.DeserializeObject<List<Urun>>(json);
    }
}

Bu işlemler sayesinde stok verileri kalıcı hale gelir ve uygulama her açıldığında önceki veriler yüklenebilir.

Sonuç

C# ile geliştirilen bu basit stok takip sistemi, nesne yönelimli programlamanın temellerini öğrenmek isteyenler için iyi bir başlangıçtır. Sistemin temel fonksiyonları olan ekleme, güncelleme, silme ve listeleme işlemleri kolaylıkla yapılabilmektedir. Daha ileri seviye bir sistem için veritabanı entegrasyonu, kullanıcı doğrulama ve grafiksel arayüz gibi özellikler eklenebilir.


C# Dilinde Basit Şifreleme Ve Veri Güvenliği Yöntemleri

C# dilinde şifreleme ve veri güvenliği, uygulamaların güvenli veri işleme yapabilmesi için hayati öneme sahiptir. Özellikle kullanıcı bilgileri, parolalar ve hassas verilerin korunması gereken durumlarda, .NET Framework ve .NET Core içerisinde bulunan kriptografi kütüphaneleri büyük kolaylık sağlar. Bu makalede, C# kullanarak veri güvenliğini nasıl sağlayacağınızı, temel şifreleme yöntemlerini ve bunların uygulamalı örneklerini adım adım inceleyeceğiz.

C# Şifreleme Temelleri

C#’da şifreleme işlemleri genellikle System.Security.Cryptography namespace’i altında yer alan sınıflar ile yapılır. Bu namespace içerisinde simetrik ve asimetrik şifreleme, hash fonksiyonları, dijital imzalar gibi pek çok güvenli veri işleme yöntemi bulunur.

Simetrik Şifreleme

Simetrik şifreleme, aynı anahtarın hem şifreleme hem de şifre çözme işlemlerinde kullanılmasıdır. C#’da bu işlem için genellikle AES (Advanced Encryption Standard) algoritması kullanılır.

AES Şifreleme Örneği

using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;

public class AesEncryption
{
    public static byte[] Encrypt(string plainText, byte[] key, byte[] iv)
    {
        using (Aes aes = Aes.Create())
        {
            aes.Key = key;
            aes.IV = iv;

            ICryptoTransform encryptor = aes.CreateEncryptor(aes.Key, aes.IV);

            using (MemoryStream ms = new MemoryStream())
            {
                using (CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
                {
                    using (StreamWriter sw = new StreamWriter(cs))
                    {
                        sw.Write(plainText);
                    }
                    return ms.ToArray();
                }
            }
        }
    }

    public static string Decrypt(byte[] cipherText, byte[] key, byte[] iv)
    {
        using (Aes aes = Aes.Create())
        {
            aes.Key = key;
            aes.IV = iv;

            ICryptoTransform decryptor = aes.CreateDecryptor(aes.Key, aes.IV);

            using (MemoryStream ms = new MemoryStream(cipherText))
            {
                using (CryptoStream cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read))
                {
                    using (StreamReader sr = new StreamReader(cs))
                    {
                        return sr.ReadToEnd();
                    }
                }
            }
        }
    }
}

Asimetrik Şifreleme

Asimetrik şifrelemede iki anahtar kullanılır: biri herkese açık (public key), diğeri gizli (private key). C#’da bu tür işlemler RSA sınıfı ile gerçekleştirilir. RSA hem veri şifreleme hem de dijital imza için kullanılabilir.

RSA Şifreleme ve Deşifreleme Örneği

using System;
using System.Security.Cryptography;
using System.Text;

public class RsaEncryption
{
    public static void EncryptAndDecryptExample()
    {
        using (RSA rsa = RSA.Create())
        {
            string original = "Bu gizli bir mesajdır.";
            byte[] data = Encoding.UTF8.GetBytes(original);

            // Şifreleme
            byte[] encrypted = rsa.Encrypt(data, RSAEncryptionPadding.Pkcs1);

            // Deşifreleme
            byte[] decrypted = rsa.Decrypt(encrypted, RSAEncryptionPadding.Pkcs1);
            string decryptedString = Encoding.UTF8.GetString(decrypted);

            Console.WriteLine($"Orijinal: {original}");
            Console.WriteLine($"Şifreli: {Convert.ToBase64String(encrypted)}");
            Console.WriteLine($"Çözülmüş: {decryptedString}");
        }
    }
}

Hash Fonksiyonları

Veri bütünlüğünü kontrol etmek ve parolaları güvenli şekilde saklamak için hash fonksiyonları kullanılır. C#’da en yaygın kullanılan hash algoritmaları SHA256 ve MD5‘dir. Ancak güvenlik açısından MD5 artık önerilmemektedir.

SHA256 ile Hash Oluşturma

using System;
using System.Security.Cryptography;
using System.Text;

public class HashingExample
{
    public static string ComputeSha256Hash(string rawData)
    {
        using (SHA256 sha256Hash = SHA256.Create())
        {
            byte[] bytes = sha256Hash.ComputeHash(Encoding.UTF8.GetBytes(rawData));

            StringBuilder builder = new StringBuilder();
            for (int i = 0; i < bytes.Length; i++)
            {
                builder.Append(bytes[i].ToString("x2"));
            }
            return builder.ToString();
        }
    }
}

Parola Güvenliği

Parolalar veritabanında düz metin olarak saklanmamalıdır. Bunun yerine, parolalar güvenli hash algoritmalarıyla (örneğin PBKDF2) işlenerek saklanmalıdır. C#’da bu işlem için Rfc2898DeriveBytes sınıfı kullanılır.

PBKDF2 ile Parola Hashleme

using System;
using System.Security.Cryptography;
using System.Text;

public class PasswordHasher
{
    public static string HashPassword(string password)
    {
        byte[] salt;
        byte[] buffer2;
        using (Rfc2898DeriveBytes bytes = new Rfc2898DeriveBytes(password, 0x10, 0x3e8, HashAlgorithmName.SHA256))
        {
            salt = bytes.Salt;
            buffer2 = bytes.GetBytes(0x20);
        }
        byte[] dst = new byte[0x31];
        Buffer.BlockCopy(salt, 0, dst, 1, 0x10);
        Buffer.BlockCopy(buffer2, 0, dst, 0x11, 0x20);
        return Convert.ToBase64String(dst);
    }

    public static bool VerifyPassword(string password, string hashedPassword)
    {
        byte[] buffer4 = Convert.FromBase64String(hashedPassword);
        byte[] dst = new byte[0x10];
        Buffer.BlockCopy(buffer4, 1, dst, 0, 0x10);
        byte[] buffer2 = new byte[0x20];
        Buffer.BlockCopy(buffer4, 0x11, buffer2, 0, 0x20);

        using (Rfc2898DeriveBytes bytes = new Rfc2898DeriveBytes(password, dst, 0x3e8, HashAlgorithmName.SHA256))
        {
            byte[] buffer3 = bytes.GetBytes(0x20);
            return buffer3.SequenceEqual(buffer2);
        }
    }
}

Veri Güvenliği İçin En İyi Uygulamalar

  • AES gibi güçlü simetrik şifreleme algoritmalarını kullanın.
  • RSA gibi asimetrik algoritmalar ile anahtar paylaşımını güvenli hale getirin.
  • Parolaları asla düz metin olarak saklamayın; PBKDF2, bcrypt veya scrypt gibi güçlü hash fonksiyonlarını kullanın.
  • Her şifreleme işlemi için farklı IV (Initialization Vector) kullanın.
  • Hash doğrulamalarında zaman-sabit karşılaştırma (timing-safe comparison) kullanarak saldırıları engelleyin.

Sonuç

C# dilinde şifreleme ve veri güvenliği işlemleri, doğru araçlar ve yöntemler kullanılarak oldukça güvenli hale getirilebilir. AES, RSA ve SHA256 gibi algoritmalar, verilerinizi korumak için güçlü birer seçenektir. Özellikle parola saklama, veri bütünlüğü ve güvenli veri aktarımı gibi işlemler için bu yöntemlerin bilinçli ve doğru bir şekilde kullanılması, uygulamaların siber tehditlere karşı direncini artırır.


C# Dilinde Kod Optimizasyonu Ve Performans Artırma Teknikleri

C# dilinde yazılan uygulamaların performansını artırmak ve daha verimli hale getirmek, özellikle büyük ölçekli sistemlerde kritik öneme sahiptir. Kod optimizasyonu, uygulamanın daha hızlı çalışmasını sağlarken, kaynak kullanımını da minimize eder. Bu makalede, C# geliştiricilerinin uygulamalarının performansını artırmak için kullanabileceği temel ve ileri düzey teknikler detaylı olarak ele alınacaktır.

Kod Optimizasyonu ve Performans Artışının Önemi

Yazılım geliştirme sürecinde performans, kullanıcı deneyimi ve sistem kaynaklarının verimli kullanımı açısından büyük önem taşır. C# gibi yüksek seviyeli dillerde, kolaylıkla yazılan kodlar bazen gereğinden fazla kaynak tüketebilir veya yavaştır. Bu nedenle kod optimizasyonu, bellek yönetimi, algoritma seçimleri ve uygulama mimarisi gibi unsurların dikkatlice değerlendirilmesi gerekir. Uygulamanın daha hızlı ve verimli çalışması, hem kullanıcı memnuniyetini artırır hem de sistem maliyetlerini düşürür.

Veri Yapılarının Doğru Kullanımı

C#’da performans artışının en temel yollarından biri, doğru veri yapısının seçilmesidir. Örneğin, çok sayıda veri üzerinde hızlı arama yapılması gereken bir senaryoda List<T> yerine Dictionary<TKey, TValue> veya HashSet<T> kullanmak büyük fark yaratır. List.Contains() metodu O(n) karmaşıklığına sahipken, HashSet.Contains() O(1)’dir.

Ayrıca, sabit boyutlu veri setleri için Span<T> ve Memory<T> gibi yapılar bellek kopyalama işlemlerini azaltarak performansı artırır. Özellikle büyük veri setleriyle çalışırken bu yapılar verimsiz bellek işlemlerini en aza indirir.

Bellek Yönetimi ve Garbage Collector (GC) Optimizasyonu

C#’da bellek yönetimi, Garbage Collector tarafından otomatik olarak yapılır. Ancak bu, bellek yönetimini tamamen ihmal edebileceğiniz anlamına gelmez. Sık nesne üretimi, özellikle kısa ömürlü nesnelerin sürekli oluşturulması, GC üzerinde ciddi bir yük oluşturur. Bu da uygulama performansında düşüşe neden olur.

Performansı artırmak için şunlar yapılabilir:

  • String birleştirme işlemlerinde StringBuilder kullanılmalı. Çünkü string’ler immutable’dır ve her birleştirme yeni bir nesne üretir.
  • Nesne havuzu (object pooling) ile nesnelerin tekrar tekrar oluşturulması engellenebilir.
  • using blokları ile IDisposable nesnelerin zamanında serbest bırakılması sağlanır.

Algoritma ve Kod Akışı Optimizasyonu

Performans açısından en dikkat edilmesi gereken konulardan biri de kullanılan algoritmalardır. Örneğin, iç içe döngüler yerine LINQ ifadeleri daha okunabilir olsa da, bazı durumlarda performans kaybına yol açabilir. LINQ sorguları, özellikle büyük veri setleri üzerinde çalışırken, gecikmeli çalıştırma (deferred execution) nedeniyle beklenmedik maliyetler doğurabilir.

Bazı öneriler:

  • Döngülerde mümkünse for yerine foreach kullanmaktan kaçınılmalı, çünkü bazı koleksiyonlarda boxing/unboxing işlemlerine neden olabilir.
  • Karşılaştırma işlemlerinde Equals() yerine ReferenceEquals() kullanmak, nesne eşitliği kontrolünde performans kazancı sağlar.
  • Gereksiz sorgu çalıştırılmamalıdır. Örneğin, .Count() yerine .Any() kullanmak, sadece veri olup olmadığını kontrol ederken büyük fark yaratır.

Asenkron Programlama ve Paralel İşlem

Asenkron programlama (async/await) ve paralel işlem teknikleri (Task Parallel Library – TPL), uygulamanın yanıt verme süresini azaltır ve kaynak kullanımını optimize eder. Özellikle I/O işlemleri (veritabanı, dosya okuma/yazma, ağ çağrıları) sırasında asenkron yapılar kullanmak, ana iş parçacığını bloklamaz.

Örnek olarak:

public async Task<string> GetDataAsync()
{
    using var client = new HttpClient();
    return await client.GetStringAsync("https://example.com/data");
}

Ayrıca Parallel.For ve Parallel.ForEach gibi yapılar, çok çekirdekli sistemlerde işlem yükünü dağıtarak performansı artırabilir. Ancak bu yapıların kullanımı dikkatli olunmalıdır; çünkü thread güvenliği ve senkronizasyon sorunları yaratabilir.

Derleme ve Runtime Optimizasyonları

C# derleyicisinin sunduğu bazı optimizasyonlar, kodun çalışma zamanındaki performansını artırabilir. Örneğin Release modda derlenen projelerde JIT derleyicisi kodu daha optimize şekilde derler. Debug modda ise çeşitli debug kontrolleri nedeniyle performans düşer.

Runtime tarafında da şu optimizasyonlar uygulanabilir:

  • unsafe kodlar ile işaretçi (pointer) kullanımı, bazı performans kritik senaryolarda hız kazandırabilir.
  • struct yerine class kullanmak, heap üzerinde fazla nesne oluşturulmaması için tercih edilebilir.
  • readonly, const ve static readonly yapıları ile değişmez veriler önceden tanımlanarak performans artırılabilir.

Profil ve Benchmark Araçları Kullanımı

Kodun performansını artırmak için, önce hangi bölümlerde yavaşlama olduğunu anlamak gerekir. Bu noktada Visual Studio’nun Diagnostic Tools, JetBrains dotTrace ya da BenchmarkDotNet gibi araçlar devreye girer. Özellikle BenchmarkDotNet, kod parçalarının ne kadar sürede çalıştığını detaylı olarak ölçer ve karşılaştırır.

Örnek kullanım:

[Benchmark]
public int SumWithForLoop()
{
    int sum = 0;
    for (int i = 0; i < 1000; i++)
        sum += i;
    return sum;
}

Sonuç

C# dilinde kod optimizasyonu ve performans artırma teknikleri, uygulamanın kullanıcı dostu, kaynak dostu ve sürdürülebilir olmasını sağlar. Doğru veri yapılarını seçmek, bellek yönetimine dikkat etmek, asenkron yapıları kullanmak ve kodunuzu profil araçlarıyla ölçmek, bu konuda başarılı olmanızı sağlar. Performans odaklı geliştirme, sadece büyük sistemlerde değil, tüm uygulamalarda dikkate alınması gereken bir disiplindir.


C# Dilinde Bellek Yönetimi Ve Garbage Collector

C# dilinde bellek yönetimi, otomatik olarak çalışan Garbage Collector (Çöp Toplayıcı) tarafından gerçekleştirilir. Bu sistem, geliştiricilerin manuel olarak bellek ayırmak ve serbest bırakmak zorunda kalmadan daha güvenli ve verimli uygulamalar yazmalarını sağlar. Ancak, bu işlemin nasıl çalıştığını anlamak performans optimizasyonu açısından büyük önem taşır.

Bellek Yönetimi Nedir?

Bellek yönetimi, bir programın çalışması sırasında ihtiyaç duyduğu bellek alanlarının kontrolünü ve düzenlenmesini ifade eder. C# gibi yönetilen (managed) dillerde, bellek yönetimi .NET Runtime tarafından otomatik olarak gerçekleştirilir. Bellek iki ana bölümden oluşur: stack ve heap.

Stack Bellek

Stack bellek, derleme zamanında boyutu belirlenen ve yaşam süresi kısa olan veriler için kullanılır. Metot çağrımları, yerel değişkenler ve değer türleri (int, bool, struct vb.) stack üzerinde saklanır. Stack, LIFO (Last In, First Out) prensibiyle çalışır ve veriler hızlı bir şekilde belleğe yerleştirilip kaldırılır.

Heap Bellek

Heap bellek, dinamik olarak oluşturulan ve yaşam süresi uzun olan veriler için kullanılır. Referans türleri (class, string, object vb.) heap üzerinde saklanır. C#’da heap üzerindeki veriler Garbage Collector tarafından yönetilir. Nesneler oluşturulduğunda heap’e yerleştirilir, kullanılmadıklarında ise otomatik olarak silinir.

Garbage Collector (Çöp Toplayıcı) Nedir?

Garbage Collector (GC), .NET Framework’ün ve .NET Core/.NET 5+’ın önemli bir parçasıdır. Uygulama tarafından artık kullanılmayan nesneleri heap bellekten otomatik olarak temizleyerek bellek sızıntısı (memory leak) gibi sorunların önüne geçer. GC, referans sayımı yapmaz; bunun yerine, nesnelerin kök (root) nesnelerden erişilebilirliğini kontrol eder.

GC Nasıl Çalışır?

Garbage Collector, üç temel aşamadan oluşur:

  • Mark (İşaretleme): Kök nesnelerden ulaşılamayan tüm nesneler işaretlenir.
  • Sweep (Temizleme): İşaretlenen nesneler heap’ten kaldırılır.
  • Compact (Sıkıştırma): Geriye kalan nesneler bellekte sıkıştırılarak boşluklar kapatılır.

GC Nesil Sistemine Göre Çalışır

.NET Garbage Collector, nesneleri yaşlarına göre sınıflandıran bir nesil (generation) sistemine sahiptir:

  • Generation 0: Yeni oluşturulan ve henüz toplanmamış nesneleri içerir. Bu nesiller en sık toplanır.
  • Generation 1: Generation 0’da toplandıktan sonra hayatta kalan nesneler buraya taşınır. GC geçişleri arasında bir tampon görevi görür.
  • Generation 2: Uzun ömürlü nesnelerin bulunduğu bölümdür. Bu nesiller daha seyrek toplanır.

Bellek Yönetimi Süreci

Bellek yönetimi süreci, bir nesne oluşturulduğunda başlar. Nesne heap üzerinde tahsis edilir ve uygulama tarafından kullanılır. Nesne artık kullanılmadığında, referansı kök nesnelerden kopar ve ulaşılabilir olmaktan çıkar. GC bu nesneyi bir sonraki toplama sırasında bellekten kaldırır.

Örnek:

public class MyClass
{
    public string Data { get; set; }
}

class Program
{
    static void Main()
    {
        MyClass obj = new MyClass(); // Heap'te nesne oluşturulur
        obj.Data = "Merhaba";
        obj = null; // Artık nesneye erişim yok
        // GC çalıştığında bu nesne toplanır
    }
}

Garbage Collector’ün Tetiklenmesi

GC, aşağıdaki koşullarda otomatik olarak tetiklenir:

  • Heap belleğin dolması.
  • System.GC.Collect() metodunun çağrılması (bu yöntem önerilmez).
  • Sistem kaynaklarının düşük olması.

Performans Üzerindeki Etkisi

GC, otomatik bellek yönetimi sağlasa da performans üzerinde bazı etkileri olabilir. Özellikle büyük nesnelerle veya yüksek frekansta nesne oluşturulması durumunda GC’nin sık çalışması, uygulama performansında düşüşlere neden olabilir. Bu nedenle bellek yönetimi en iyi uygulamaları dikkate alınmalıdır:

  • Nesne oluşturmadan önce ihtiyaç gerçekten olup olmadığı değerlendirilmelidir.
  • Küçük nesneler yerine, nesne havuzları (object pooling) kullanılabilir.
  • Uzun süreli nesnelerin gereksiz yere Generation 0’da kalmaması sağlanmalıdır.

GC İzleme ve Optimizasyon

Uygulama performansını artırmak için GC davranışını izlemek önemlidir. Bunun için aşağıdaki araçlar kullanılabilir:

  • Performance Monitor (PerfMon): .NET sayaçlarıyla GC aktivitelerini izlemek için kullanılır.
  • dotMemory, Visual Studio Diagnostic Tools: Bellek kullanımını detaylı analiz eder.
  • ETW (Event Tracing for Windows): GC olaylarını gerçek zamanlı olarak izlemeye yarar.

Sonuç

C# dilinde bellek yönetimi, Garbage Collector sayesinde büyük ölçüde otomatik hale gelmiştir. Ancak bu, geliştiricilerin bellek yönetimine dair hiçbir şey bilmeden yazdıkları kodların her zaman verimli olacağı anlamına gelmez. GC’nin nasıl çalıştığını ve performans üzerindeki etkilerini anlamak, daha sağlam ve hızlı uygulamalar geliştirmek açısından kritik öneme sahiptir. Bellek kullanımını optimize ederek hem kaynak tasarrufu sağlayabilir hem de kullanıcı deneyimini artırabilirsiniz.


C# Dilinde Dosya Okuma/Yazma Işlemleri

C# programlama dili, dosya işlemleri için güçlü ve esnek yöntemler sunar. Sistem dosyalarına erişim, veri okuma ve yazma işlemleri hem temel seviyede hem de yüksek seviyede kolaylıkla yapılabilmektedir. Bu makalede, C# kullanarak dosya okuma ve yazma işlemlerinin nasıl yapıldığı detaylı olarak ele alınacaktır.

Dosya İşlemlerine Giriş

Dosya işlemleri, bir uygulamanın verileri kalıcı olarak saklamasını ve bu verilere daha sonra erişmesini sağlar. C# dilinde dosya işlemleri genellikle System.IO namespace’i kullanılarak gerçekleştirilir. Bu namespace içerisinde bulunan File, FileInfo, StreamReader, StreamWriter gibi sınıflar, dosya okuma ve yazma süreçlerini kolaylaştırır.

File Sınıfı ile Basit Dosya İşlemleri

File sınıfı, dosya işlemleri için en basit ve hızlı yolu sunar. Bu sınıf sayesinde bir dosyanın tamamını okuyabilir veya yazabilirsiniz. Örneğin, bir metin dosyasının içeriğini okumak için File.ReadAllText() metodu kullanılabilir:

string content = File.ReadAllText("ornek.txt");

Aynı şekilde, bir dosyaya veri yazmak için File.WriteAllText() metodu kullanılabilir:

File.WriteAllText("ornek.txt", "Merhaba Dünya!");

Bu yöntemler, küçük boyutlu dosyalar için oldukça etkili olsa da büyük dosyalar için bellek sorunlarına neden olabilir. Bu nedenle büyük dosyalarla çalışırken daha gelişmiş yöntemler tercih edilmelidir.

StreamReader ve StreamWriter Kullanımı

StreamReader ve StreamWriter sınıfları, dosya işlemlerinde daha fazla kontrol ve performans sağlar. Özellikle büyük metin dosyalarında veri satır satır okunabilir ya da yazılabilir. Bu sınıflar, veri akışlarını yöneterek bellek kullanımını optimize eder.

Aşağıdaki örnek, bir dosyayı satır satır okumayı göstermektedir:


using (StreamReader reader = new StreamReader("ornek.txt"))
{
    string line;
    while ((line = reader.ReadLine()) != null)
    {
        Console.WriteLine(line);
    }
}
    

Benzer şekilde, StreamWriter kullanarak satır satır veri yazılabilir:


using (StreamWriter writer = new StreamWriter("ornek.txt"))
{
    writer.WriteLine("İlk satır");
    writer.WriteLine("İkinci satır");
}
    

using bloğu, kaynakların doğru şekilde serbest bırakılmasını sağlar. Bu yapı, dosya işlemlerinde hata yönetimi açısından da oldukça güvenlidir.

FileInfo ve DirectoryInfo Sınıfları

FileInfo ve DirectoryInfo sınıfları, dosya ve dizinlerle ilgili daha detaylı bilgi almak veya işlem yapmak için nesne yönelimli bir yaklaşım sunar. FileInfo nesnesi oluşturularak dosya üzerinde çeşitli işlemler yapılabilir:


FileInfo fileInfo = new FileInfo("ornek.txt");
if (fileInfo.Exists)
{
    Console.WriteLine($"Dosya boyutu: {fileInfo.Length} byte");
}
    

Benzer şekilde, DirectoryInfo ile dizin işlemleri yönetilebilir. Bu sınıflar, dosya ve dizinlerin oluşturulması, silinmesi, taşınması gibi işlemleri de destekler.

İkili Dosya İşlemleri

C# ile yalnızca metin dosyaları değil, ikili (binary) dosyalar da okunabilir ve yazılabilir. FileStream sınıfı, bu tür işlemler için kullanılır. Özellikle resim, ses veya video gibi dosyaların işlenmesi sırasında FileStream tercih edilir.

Aşağıdaki örnek, bir ikili dosyanın okunmasını ve başka bir dosyaya yazılmasını göstermektedir:


using (FileStream inputStream = new FileStream("giris.jpg", FileMode.Open, FileAccess.Read))
using (FileStream outputStream = new FileStream("cikis.jpg", FileMode.Create, FileAccess.Write))
{
    byte[] buffer = new byte[1024];
    int bytesRead;
    while ((bytesRead = inputStream.Read(buffer, 0, buffer.Length)) > 0)
    {
        outputStream.Write(buffer, 0, bytesRead);
    }
}
    

Bu örnekte, dosya içeriği 1024 byte’lık parçalar halinde okunup yazılır. Bu yöntem, büyük dosyaların işlenmesinde verimliliği artırır.

Hata Yönetimi ve Güvenlik

Dosya işlemleri sırasında oluşabilecek hatalar için uygun istisna yönetimi yapılmalıdır. FileNotFoundException, DirectoryNotFoundException, UnauthorizedAccessException gibi özel istisnalar ile hata durumları yönetilebilir.


try
{
    string content = File.ReadAllText("varolmayan.txt");
}
catch (FileNotFoundException)
{
    Console.WriteLine("Dosya bulunamadı.");
}
catch (UnauthorizedAccessException)
{
    Console.WriteLine("Dosyaya erişim izniniz yok.");
}
    

Ayrıca, kullanıcı girdilerinden gelen dosya yolları doğrulanmalı ve dosya işlemlerinde güvenlik açıklarına karşı önlem alınmalıdır. Güvensiz dosya yolları, uygulama içinde beklenmedik erişimlerin yapılmasına neden olabilir.

Performans ve En İyi Uygulamalar

Dosya işlemlerinde performansı artırmak için bazı en iyi uygulamalar vardır. Öncelikle, using blokları ile kaynakların doğru şekilde serbest bırakılması gerekir. Ayrıca, büyük dosyaları tek seferde okumak yerine parça parça işlemek daha verimlidir.

Gereksiz dosya erişimlerinden kaçınılmalı, işlemler önbelleğe alınabiliyorsa bu yöntemler tercih edilmelidir. Dosya işlemleri sırasında asenkron metotlar (ReadAllTextAsync, WriteAllTextAsync) kullanmak da performansı artırabilir.

Sonuç

C# dilinde dosya okuma ve yazma işlemleri, uygulamaların veri yönetimi açısından esnekliğini artırır. System.IO kütüphanesindeki sınıflar sayesinde hem metin hem de ikili dosyalar üzerinde güvenli ve verimli işlemler yapılabilir. Doğru hata yönetimi ve performans optimizasyonu ile dosya işlemleri uygulamaların daha sağlam çalışmasını sağlar.


C# Dilinde Asp.Net Core Ile Web Uygulamalarına Geçiş

ASP.NET Core, Microsoft’un modern, açık kaynaklı ve platformlar arası web uygulama geliştirme framework’üdür. C# diliyle yazılmış uygulamaların yüksek performanslı, güvenli ve ölçeklenebilir şekilde web ortamına taşınmasını sağlar. Bu makalede, ASP.NET Core ile web uygulamalarına nasıl geçiş yapılacağı, temel yapılandırmalar ve avantajları detaylı olarak ele alınacaktır.

ASP.NET Core Nedir?

ASP.NET Core, .NET Framework’ün yerine geçen ve daha modüler yapıda tasarlanmış bir framework’tür. İlk olarak 2016 yılında yayınlanan bu yapı, daha önceki ASP.NET sürümlerinden önemli farklılıklar gösterir. En belirgin farklardan biri, platform bağımsız olmasıdır; yani Windows dışındaki işletim sistemlerinde de çalışabilir. Ayrıca modüler yapısı sayesinde sadece ihtiyaç duyulan bileşenler yüklenebilir, bu da uygulamaların boyutunu ve performansını optimize eder.

Neden ASP.NET Core Kullanılır?

Geleneksel ASP.NET uygulamaları sadece Windows tabanlı sunucularda çalışabildiği için esneklik açısından sınırlıydı. ASP.NET Core ile bu durum değişti. Hem Linux hem macOS üzerinde çalışabilen bu yapı, Docker konteynerleri ile de uyumlu hale geldi. Ayrıca, daha hızlı HTTP işlem süreçleri, yerleşik dependency injection desteği, middleware mimarisi ve Razor Pages gibi yenilikler, geliştiricilere daha verimli bir ortam sunar.

ASP.NET Core ile Web Uygulaması Oluşturmak

Bir ASP.NET Core projesi oluşturmak için öncelikle .NET SDK yüklü olmalıdır. Ardından komut satırından aşağıdaki komut çalıştırılır:

dotnet new webapp -n MyWebApp

Bu komut, Razor Pages tabanlı bir web uygulaması oluşturur. Dilerseniz, farklı şablonlar da kullanılabilir:

  • mvc: Model-View-Controller mimarisi kullanan bir uygulama
  • webapi: RESTful API geliştirmek için
  • blazor: C# ile istemci tarafı web uygulamaları geliştirmek için

Startup.cs ve Middleware Mimarisi

ASP.NET Core uygulamalarında yapılandırma işlemleri genellikle Startup.cs dosyası üzerinden yapılır. Bu dosya iki temel metoda sahiptir:

  • ConfigureServices: Uygulama servislerinin tanımlandığı yerdir. Dependency injection container’ına servisler burada eklenir.
  • Configure: HTTP request pipeline’ının yapılandırıldığı yerdir. Middleware bileşenleri burada sıralanır.

Örneğin, bir middleware bileşeni şu şekilde tanımlanabilir:

app.UseAuthentication();
app.UseAuthorization();
app.UseRouting();
app.UseEndpoints(endpoints =>
{
    endpoints.MapRazorPages();
});

Bu yapı sayesinde her istek için yapılacak işlemler net bir şekilde sıralanır ve özelleştirilebilir.

Razor Pages ve MVC

ASP.NET Core iki temel geliştirme modelini destekler: Razor Pages ve MVC. Razor Pages, sayfa bazlı uygulamalar için daha basit bir yapı sunarken, MVC büyük ve karmaşık projelerde daha fazla kontrol sağlar. Her iki model de Razor syntax’ını kullanır ve C# ile HTML’in harmanlandığı dinamik sayfalar oluşturmayı sağlar.

Razor Pages örneği:

@page
@model IndexModel
<h1>Hoşgeldiniz @Model.UserName</h1>

Burada @page direktifi sayesinde bu dosya doğrudan bir HTTP endpoint olarak davranır.

Dependency Injection

ASP.NET Core, dependency injection (DI) özelliğini doğrudan destekler. Bu sayede servislerin yaşam döngüsünü yönetmek ve bileşenler arasında bağımlılıkları azaltmak kolaylaşır. Örneğin, bir veritabanı servisini uygulamaya şu şekilde ekleyebilirsiniz:

services.AddScoped<IUserRepository, UserRepository>();

Bu yapı sayesinde, ilgili servis otomatik olarak sınıfların constructor’larına enjekte edilir:

public class IndexModel : PageModel
{
    private readonly IUserRepository _userRepository;
    public IndexModel(IUserRepository userRepository)
    {
        _userRepository = userRepository;
    }
}

Veri Erişimi ve Entity Framework Core

ASP.NET Core, veri erişimi için Entity Framework Core kullanır. EF Core, veritabanı ile etkileşimi kolaylaştıran, ORM (Object-Relational Mapping) tabanlı bir framework’tür. Veritabanı modelleri C# sınıfları olarak tanımlanır ve LINQ sorguları ile veri işlemi yapılır.

Örnek model:

public class User
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Email { get; set; }
}

DbContext örneği:

public class AppDbContext : DbContext
{
    public AppDbContext(DbContextOptions<AppDbContext> options) : base(options)
    {
    }

    public DbSet<User> Users { get; set; }
}

Uygulamayı Yayınlama ve Dağıtım

ASP.NET Core uygulamaları, farklı platformlara kolayca dağıtılabilir. dotnet publish komutu ile uygulama derlenir ve gerekli dosyalar çıktı dizinine kopyalanır:

dotnet publish -c Release -o ./publish

Bu dosyalar, IIS, Nginx, Apache gibi farklı web sunucularında çalıştırılabilir. Ayrıca Docker imajı haline getirilerek konteyner ortamında çalıştırılabilir:

FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base
WORKDIR /app
EXPOSE 80

FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
WORKDIR /src
COPY ["MyWebApp.csproj", "."]
RUN dotnet restore "MyWebApp.csproj"
COPY . .
RUN dotnet build "MyWebApp.csproj" -c Release -o /app/build

FROM build AS publish
RUN dotnet publish "MyWebApp.csproj" -c Release -o /app/publish

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "MyWebApp.dll"]

Performans ve Güvenlik

ASP.NET Core, yüksek performans sunar çünkü hafif bir runtime üzerine kuruludur. Kestrel adı verilen dahili web sunucusu sayesinde uygulamalar çok daha hızlı çalışır. Ayrıca middleware tabanlı güvenlik yapıları, HTTPS zorlama, CORS politikaları ve kimlik doğrulama gibi konuları kolayca yönetebilirsiniz.

Sonuç

ASP.NET Core, C# ile web uygulamaları geliştirmek isteyenler için güçlü ve esnek bir platform sunar. Platform bağımsız yapısı, modüler mimarisi ve modern geliştirme yaklaşımları sayesinde, kurumsal çözümlerden küçük projelere kadar her ölçekte uygulama geliştirilebilir. Razor Pages, MVC, DI ve EF Core gibi yapılar ise geliştirme sürecini hızlandırır ve daha temiz kod yazılmasını sağlar. Bu nedenle, C# ile web dünyasına adım atmak isteyenler için ASP.NET Core en doğru tercihtir.


© 2002 kiziltas.com - Kamil KIZILTAŞ. Her hakkı saklıdır.