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

.NET 8 – Method Çağrılarını Interceptor’larla Değiştirme

Merhaba,

Bu içeriğimizde .NET 8’de C# 12 ile birlikte gelen Interceptor özelliğini inceliyor olacağız.

Interceptor Nedir? Neden Bu Yapılanmaya İhtiyacımız Vardır?

Interceptor, uygulamadaki herhangi bir metoda yapılan çağrıyı alternatif başka bir metotla değiştirmemize ya da ilgili metodun işlevini engellememize yarayan, yazılımsal yaklaşımlar açısından aşina olduğumuz lakin programlama dili açısından ise C# 12 ile hayatımıza giren ilginç ve yeni bir deneysel özelliktir.

Interceptor’lar, önceki .NET 8 – Minimal API Ahead of Time(AOT) Compilation Template başlıklı makalemizde incelediğimiz AOT için olmasa da esasında AOT merkezli düşünce neticesinde tasarlanmış yapılardır diyebiliriz. Çünkü interceptor’ları kullanarak, daha önce AOT dostu olmayan kodu alabilir ve onu source generator tarafından oluşturulan bir sürümle değiştirebilme şansını elde edebiliriz.

Şimdi interceptor’ları daha iyi bir şekilde anlayabilmek için basit bir örnek üzerinden yapıyı gözlemleyelim.

Basit Bir Örnek Üzerinden Interceptor Kullanımı

Interceptor’lar her ne kadar source generator’lar için tasarlanmış olsa da burada basitlik adına ham bir interceptor oluşturmaya odaklanacak ve olayı özetlemiş olacağız.

Her şeyden önce .NET 8 Preview framework’ün de herhangi bir proje oluşturmanız gerekmektedir. Şahsen ben deniz sıradan bir Console Application üzerinden örneklendirme yapıyor olacağım.

İlk olarak oluşturduğunuz projede interceptor’ları kullanılabilir hale getirmek için uygulamanın .csproj dosyasında <Features>InterceptorsPreview</Features> öğesinin ayarlanması gerekmektedir.

<Project Sdk="Microsoft.NET.Sdk">

	<PropertyGroup>
		<OutputType>Exe</OutputType>
		<TargetFramework>net8.0</TargetFramework>
		<ImplicitUsings>enable</ImplicitUsings>
		<Nullable>enable</Nullable>
		<Features>InterceptorsPreview</Features>
	</PropertyGroup>

</Project>

Ardından uygulamada System.Runtime.CompilerServices namespace’i içerisinde aşağıdaki attribute’un tanımlanması gerekmektedir. Bu attribute, interceptor’ın davranışını farklı bir metoda yönlendirmemizi sağlayacak olan yapılanmanın ta kendisidir. Ancak henüz hiçbir yerde herhangi bir base class library’sine(BCL) dahil edilmediğinden dolayı bu attribute’u kendinizin tanımlaması gerekmektedir.

namespace System.Runtime.CompilerServices
{
    [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
    sealed class InterceptsLocationAttribute(string filePath, int line, int column) : Attribute
    {

    }
}

Attribute’u incelerseniz eğer interceptor’ın hangi dosyadaki(filePath), kaçıncı satır(line) ve kolondaki(column) komutlar için devreye gireceğini ifade edecek alanlar tanımlanmış vaziyettedir.

Bu tanımlamadan sonra artık interceptor’ı oluşturabilirsiniz. Bunun için misal olarak aşağıdaki içeriğe sahip olan ‘Program.cs’ dosyasını referans alırsak eğer;

X();

void X()
{
    Console.WriteLine("Laylaylom galiba sana göre sevmeler...");
}

X metoduna bir interceptor örneklendirmesi gerçekleştirebiliriz. Bunun için yapılması gereken çalışma aşağıdaki gibidir;

    static public class CodeGenerator
    {
        [InterceptsLocation(@"C:\Users\Gencay\Desktop\Interceptor.Example\Interceptor.Example\Program.cs", line: 1, column: 1)]
        static public void XInterceptor()
        {
            Console.WriteLine("Doldur be meyhaneci, boş kalmasın kadehim...");
        }
    }

Yukarıdaki kod bloğuna göz atarsanız eğer static bir sınıf oluşturulmakta ve içerisinde interceptor’la yönlendirmede bulunacak hedef metotla aynı imzaya sahip bir metot tanımı gerçekleştirilmektedir. İşte bu metot, uygulamada X metodu tetiklendiği taktirde, bu tetiklenmeyi kesecek ve araya girecek olan metottur.

Tabi burada dikkat edilmesi gereken bir husus vardır ki, o da; InterceptsLocation attribute’unu kullanırken line ve column özelliklerine verilen değerlerin kesinlikle bir metot çağrısına karşılık gelmesi gerekliliğidir. Aksi taktirde verilen değerler aşağıdaki görseldeki gibi alakasız bir noktaya/yapıya denk geliyorsa ilgili attribute hata verecektir..NET 8 - Method Çağrılarını Interceptor'larla DeğiştirmeGörselde, ‘Program.cs’ dosyası içerisinde belirtilen 3. satır 1. kolonun nereye denk geldiği gösterilmektedir. Haliyle bu durumda aşağıdakine benzer bir hata verilecektir.

The provided line and character number does not refer to an interceptable method name, but rather to token ‘void’.

Ayrıca aşağıdaki gibi birden fazla metodu aynı interceptor’a yönlendirebilirsiniz.

X();
Y();

void X()
{
    Console.WriteLine("Laylaylom galiba sana göre sevmeler...");
}

void Y()
{
    Console.WriteLine("Sende başını alıp gitme ne olur, ne olur tut ellerimi...");
}
    static public class CodeGenerator
    {
        [InterceptsLocation(@"C:\Users\Gencay\Desktop\Interceptor.Example\Interceptor.Example\Program.cs", line: 1, column: 1)]
        [InterceptsLocation(@"C:\Users\Gencay\Desktop\Interceptor.Example\Interceptor.Example\Program.cs", line: 2, column: 1)]
        static public void XInterceptor()
        {
            Console.WriteLine("Doldur be meyhaneci, boş kalmasın kadehim...");
        }
    }

Yakalanan parametreli metodun, parametre değerleri interceptor metoduna da aktarılacaktır. Buna dair örneği yazının sonunda paylaştığım github reposundaki örnek çalışmada gözlemleyebilirsiniz.

Evet, görüldüğü üzere interceptor’lar bu şekilde kullanılmaktadırlar. Burada konuya dair bilinmesi gereken sınırlılıklardan biri, interceptor’ların yalnızca metotların müdahalesine odaklanmasıyken bir diğeri ise interceptor’ın metot imzasıyla tam olarak eşleşmesi gerekliliğidir. Başka bir sınırlılık ise interceptor’lar derleme sürecinin bir parçası olarak çalıştıkları için NuGet üzerinden yüklenmiş olan harici kütüphanelerden gelen metotlara karşın yapılan çağrıları yönlendirememektedirler. Çünkü hazır kütüphanelerde gelen yapılar zaten derlendiği için bu işlem geçerli olmayacaktır. Ve sonuncu olarak da dosya yollarının tam bir path olarak belirtilme ihtiyacı Linux, macOS veya Windows ortamlarında istemsiz olsa da kesinlikle sorunlara neden olabilecektir.

Interceptor’lar tam bir AOP çözümü değildirler.

Tüm bunların dışında InterceptsLocation attribute’u ile bildirilen metot çağrılarının satır ve kolon bilgilerinin değişmesi ihtimali kodun olası hatalara her daim gebe olduğunu göstermektedir.

Nihai olarak,
Interceptor’lar sayesinde beklenen o ki, çoğu programcı açısından interceptor’lar doğrudan kullanılmayacak ancak uygulamaların daha hızlı çalışması ve kolaylıkla konuşlandırılması açısından önemli rol oynayacaktır kanaatindeyiz.

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

Not : Örnek çalışmayı aşağıdaki github adresinden indirebilirsiniz.
https://github.com/gncyyldz/CSharp12.Interceptor.Example

Bunlar da hoşunuza gidebilir...

Bir yanıt yazın

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