Derinlemesine yazılım eğitimleri için kanalımı takip edebilirsiniz...

C# 13/14 – More Partial Members: Partial Property & Partial Indexer & Partial Events & Partial Constructors

Merhaba,


Bu içeriğimizde, C# 13’de gelen partial property ve partial indexer özellikleri ile kapıların açıldığı, C# 14’de de aynı doğrultuda partial event ve partial constructor olarak devamının getirildiği More Partial Members özelliğini bütünsel olarak inceliyor olacağız.

Artık C# programlama dilinde, bir class’ın her önemli parçası bölünebilir (partial) hale getirilebilmektedir…

Büyük Resmi Görelim

Malum, C#’ın ilk sürümlerinde yalnızca class’lar partial hale getirilebiliyordu. Sonra metotlar partial olabildiler. Şimdi ise C# 13 ile property ve indexer’lar, C# 14 ile de event ve constructor’lar… Bu gelişimsel seyri şöyle özetleyebiliriz: Class ile state parçalanabiliyordu, metot ile behavior… ve şimdi ise property, indexer, event ve constructor ile de tüm lifecycle parçalanabilmektedir…

Programlama da partial, bir şeyin tanımlanmasını fiziksel olarak birden fazla dosyaya parçalayabilmektir. Detaylı bilgi için YouTube kanalımızdaki Partial Yapıları İnceleyelim başlıklı dersi izleyebilirsiniz…

C# 13 | partial property & partial indexer

Bu yenilik ile artık C#’ta property’lerle birlikte indexer’ları parçalayabilmekte, bir başka deyişle property’i bir yerde tanımlayıp, başka bir yerde implement edebilmekteyiz…

Burada temel mantık esasında aşağıdaki gibi declaring ve implementing’e yaklaşımına dayanmaktadır;

  • Declaring declaration (bildirim/imza)
    Property, gövdesiz bir şekilde imzasız tanımlanır.

    public partial string Name { get; set; }
    
    💭 Benim name diye bir şeyim olacak… ama detayını sonra izah edeceğim…
  • Implementing declaration (gerçek kod/gövde)
    Property’nin gövdesi/faaliyeti oluşturulur.

    public partial string Name { get => "Gençay"; set => field = value; }
    
    💡 Heh işte ahanda böyle çalışacak…

Tabi bu yaklaşım bütünsel olarak aşağıdaki gibi bir yapıya sahiptir ve ancak belirtilen ilkeler çerçevesinde mümkündür;

partial class PartialExample
{
    public partial string Name { get; set; }

    public partial string Name { get => "Gençay"; set => field = value; }
}

ya da

partial class PartialExample
{
    public partial string Name { get; }
}

partial class PartialExample
{
    public partial string Name => "Gençay";
}
  • Bir partial member, klasik partial mantığında olduğu gibi yine partial bir class içerisinde olmalıdır.
  • Deklerasyonların her iki tarafının da imzaları birebir aynı olmalıdır.
    public partial string Name { get; private set; }
    public partial string Name { get => “Gençay”; set => field = value; }❌
    public partial string Name { get; private set; }
    public partial string Name { get => “Gençay”; private set => field = value; }✅
    public partial string Name { get; }
    public partial string Name { get => “Gençay”; private set => field = value; }❌
    public partial string Name { get; }
    public partial string Name { get => “Gençay”; }✅
  • Declaring tarafında gövde oluşturulmaz. Yalnızca { get; set; } gibi property’nin ya da indexer’ın işlevselliğini belirleyecek imza tasarlanır.
  • Implementing tarafı ise mutlaka gerçek gövdeyi içermelidir. Yani get / set blokları olmak mecburiyetindedir. Ha bu gövdeler, istenirse yukarıdaki gibi { get; set; } şeklinde tanımlanır, istenirse de scope’lar ile normal C# blokları açılır…
  • Her partial property yahut partial indexer için bir implementing declaration tanımlanması gerekmektedir.
  • Implementing tarafında auto-property kullanılamaz! Çünkü, compiler zaten auto-property üretecektir ve bu da partial mantığıyla çakışacaktır.

Hadi bir tane de indexer için de örnek inceleyelim…

partial class PartialExample
{
    public partial string this[int index] { get; set; }
    public partial void WriteDatas();
}

partial class PartialExample
{
    private string[] _datas = new string[20];
    public partial string this[int index] { get => _datas[index]; set => _datas[index] = value; }
    public partial void WriteDatas()
        => _datas.ToList().ForEach(data => Console.WriteLine(data));
}

Partial method’larda amaç davranışı bölmekken, partial property’lerde ise veri ile birlikte davranışı bölmektir…

C# 14 | partial events & partial constructors

C# 14 ile de event’ler ve constructor metotlar partial yapılabilmektedirler. Yukarıdaki tanımlama ilkeleri doğrultusunda bu yenilikte aşağıdaki koşullarda kullanılabilmektedir…

Partial Events

Biliyorsunuz ki, normalde event’ler aşağıdaki gibi tanımlanmaktadırlar:

public event EventHandler Clicked;

Artık C# 14 ile bu event’leri iki parçaya aşağıdaki gibi bölebilmekteyiz:

Declaring;

public partial event EventHandler Clicked;
💭 Bu event var ama nasıl çalıştığını sonra anlatacağım…

Implementing;

    private EventHandler _clickedEvent;
    public partial event EventHandler Clicked
    {
        add => _clickedEvent += value;
        remove => _clickedEvent -= value;
    }

Burada kritik nokta şudur ki; normal şartlarda event’in add ve remove scope’ları compiler tarafından otomatik üretilirken, partial event’te ise bu tarafımızca override edilmektedir! Ayrıca partial events kullanımında, implementasyon tarafında add/remove scope’larının tanımlanması ekstra bir zorunluluktur!

Partial Constructors

Bu da oldukça ilginç bir yeniliktir. Evet 🙂 Constructor’da artık parçalanabilmektedir.

partial class PartialExample
{
    public partial PartialExample();
}

partial class PartialExample
{
    public partial PartialExample()
    {
        // Constructor implementation
    }
}

Bunu nerede kullanacaz la hoca? dediğinizi duyar gibiyim. Tabi ki de sıradan kod geliştirme süreçlerinde hiçbir zaman kullanmayacağımız, hatta muhtemelen unutacağımız bu özelliğin getirdiği asıl güç, nesne yaratılırken çalışan lifecycle pipeline’ını parçalama imkanı sağlamasıdır. Yani, dikkat ederseniz partial method ve partial property davranışı parçalarken, partial constructor ise lifecycle’ı parçalamaktadır.

Neden böyle bir şeye ihtiyaç var?

Bu soruya karşın cevaben dürüst olmak gerekirse, tabi ki de bu özelliklerin sıradan kod yazan geliştiriciler için olmadığını söyleyebiliriz… Bu yapı, gelecek programlama teknolojisi olan Source Generator senaryolarına eşlik edilebilmesi için dilin güncelliğini koruyabilmesi ve çağdaş yaklaşımları destekleyecek bir altyapıya sahip olabilmesi için düşünülmüş bir gelişmedir diyebiliriz.

Ne de olsa source generator; backing field’lar oluşturmakta, validation’lar eklemekte, logging yapılandırmasını sağlamakta… yani anlayacağınız adı üzerinde otomatik kod üretmektedir. Ee haliyle insani müdahalelerin otomatik üretimden etkilenip ezilmemesi için bu yapılara son derece ihtiyaç duyulmaktadır ve daha çok duyulacaktır.

Ayrıca, benzer kaygının ORM / Entity Framework Core gibi sistemlerde de ta ezelden beridir olduğu bilinir. Haliyle migration generating süreçlerinde yahut özellikle database first yaklaşımının benimsendiği çalışmalarda bu nimetlerden istifade edilmesi geliştirici açısından kodun kalitesini ve generating süreçlerine dair olan direncini son derece ideal hale getirecektir.

Ve bu gelen özelliklerle ilgili en nihai olarak; bir class için sadece kod değil, genişletilebilir bir runtime pipeline’ı sağladığını söyleyebilir ve içeriğimizi burada noktalayabiliriz.

İlgilenenlerin faydalanması dileğiyle…
Sonraki yazılarımda görüşmek üzere…
İyi çalışmalar…

Bunlar da hoşunuza gidebilir...

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir