.NET 8 – global using İle Anlık Type Tanımlama
Merhaba,
C# ile yaptığımız geliştirmelerde bazen anlık olarak elimizdeki verileri bütünsel olarak temsil edebilecek ve sadece o an için kullanacağımız bir türe ihtiyacımız olabiliyor. Bu tarz durumlarda bir class, record ya da struct tanımından ziyade o anda üretip, kullanıp ve bir daha herhangi bir noktada adı geçmeyecek bir tür oluşturabilmek ne güzel olurdu değil mi? Ee iyi de hoca bu işler için anonymous types yapılanması var ya la işte! diye söylenebilirsiniz. Evet, bu yapılanma anlık olarak eldeki verileri ihtiyacımız olan formatta temsil edebilmemizi sağlıyor sağlamasına ama her ne kadar referans türlü bir nesne oluşturmuş olsak da özellikle bir tür/type/referans olarak davranış sergilemediği için anlık ihtiyaçlarda pekte işimize yaradığını söyleyemeyiz. Şöyle ki, anonymous type olarak bir veriyi oluşturduğumuzda bu verinin bir türü olmadığı için metot dönüşümlerinde ya object ya da dynamic olarak return etmek mecburiyetinde kalıyoruz.
class Consumer
{
public dynamic GetConsumer()
{
return new
{
Name = "XConsumer",
Id = "12345667"
};
}
}
Mesela yukarıda olduğu gibi dynamic olarak return ettiğimizde, bu metodun kullanıldığı noktada tip güvenliğinden istifade edemediğimiz için geliştirici açısından ciddi zorluklar söz konusu olabiliyor. İşte bu sebepten dolayı o anlık üretilip kullanılabilir referans deyince akıllardan anonymous type’ı çıkarabiliriz.
Bu durumda gel gelelim akla birde tuple nesneler gelebilir. Evet tuple nesneler, yapısal olarak eldeki verileri ihtiyaç formatında temsil edebilen amma velakin bunu yaparken ortaya bir referanstan ziyade toplu erişim gösterilebilir bir veri yapısı ortaya koyan yapılardır.
class Consumer
{
public (string Name, string Id) GetConsumer()
{
return ("XConsumer", "12345667");
}
}
Tuple olarak yaratılan bir nesnenin field’larına tip güvenli bir şekilde erişim gösterilebildiği için, evet, belki bu söylentiyi tuple nesneler için yapsaydınız haklı olabilirdiniz.
Velhasıl kelam… C# programlama dili artık bu ihtiyacı .NET 8 ile gelmiş olan
global using özelliği sayesinde giderebilmektedir. Bizler bu yeni gelen özellik sayesinde anlık olarak ve başka hiçbir yerde kullanılmayacak referans davranışına sahip bir tür oluşturabiliyor ve ihtiyaç doğrultusunda kullanabiliyoruz. Tabi esasında bu özellik ile üretilen referansın, özünde yine bir tuple nesne olarak şekillendirildiğini baştan söylemekte fayda görmekteyim.
Şimdi olayı şöyle örneklendirelim;
class PersonHelper
{
public ? GetPerson()
{
string name = "Gençay";
string surname = "Yıldız";
int age = 32;
return ...
}
}
Yukarıdaki kod bloğuna göz atarsak eğer ‘PersonHelper’ içerisindeki ‘GetPerson’ metodunun belli başlı verileri geriye döndürmesi gerektiğini gözlemliyoruz. Burada, return sürecinde tüm verileri taşıyabilecek bir class ya da record referansı tasarlayabileceğimiz gibi bir struct’ta oluşturabiliriz. Ama bu işlem uygulama seviyesinde sade ve sadece bu noktada gerçekleştirilecekse ve başka bir yerde bu referansa ihtiyaç duyulmayacaksa işte o taktirde tuple türünden ya da .NET 8 ile gelmiş olan global using‘den istifade edebiliriz.
Şöyle ki;
Tuple ile çözüm;
class PersonHelper
{
public (string name, string surname, int age) GetPerson()
{
string name = "Gençay";
string surname = "Yıldız";
int age = 32;
return (name, surname, age);
}
}
Bu muhtemelen bu güne kadar aşina olduğumuz çözümdür.
global using ile çözüm;
global using Person = (
string Name,
string Surname,
int Age
);
class PersonHelper
{
public Person GetPerson()
{
string name = "Gençay";
string surname = "Yıldız";
int age = 32;
return new()
{
Name = name,
Surname = surname,
Age = age
};
}
}
Bu ise işte mevzu bahis olan ve .NET 8 ile gelmiş olan yeni bir davranışsal çözümdür. Burada global using ile tanımlanmış olan ‘Person’ türü uygulama seviyesinde her noktadan erişilebilmekte ve özünde tuple davranış sergilemektedir.
Böylece bizler bazen metotlarda geriye dönülecek değerleri sadece o an/o metot için oluşturmak mecburiyetinde kaldığımız durumlarda global using ile anlık olarak başka hiçbir yerde kullanılmayacak olan, özünde tuple türleri bu şekilde yaratabiliyoruz. Tabi tuple tür olduğu için kullanırken de new operatörü yerine aşağıdaki gibi tuple davranışını da bizzat uygulayabilirsiniz.
internal class PersonHelper
{
public Person GetPerson()
{
string name = "Gençay";
string surname = "Yıldız";
int age = 32;
return (name, surname, age);
}
}
Bu arada yanlış anlaşılmasın, başka hiçbir yerde kullanılmayacak derken isterseniz kullanabilirsiniz ama durumsal olarak bu yeniliğin bahsedilen tarz senaryolara özgü davranışını vurgulamak için bu şekilde bir tanımda bulunuyorum.
Ayrıca ifade etmek istediğim bir durum daha var ki, o da global using ile oluşturulan türlerin uygulama seviyesinde aşağıdaki gibi ayrı bir dosyada tanımlanmasıdır.
Misal global-using-types.cs;
global using Person = (
string Name,
string Surname,
int Age
);
global using PersonFacebookStatistic = (
int Id,
long LikeCount,
long PostCount,
long FollowersCount
);
global using PersonSalaryGraphicStatistic = (
string PersonType,
decimal SalaryRate
);
.
.
.
Bu şekilde yapılan çalışmaların hem yönetilebilirlikleri daha da kolaylaştırılmakta hem de derli toplu bir proje seyri söz konusu olmaktadır.
Tüm bu anlatılanların yanında C# 10 ile gelmiş olan Global Using Directive özelliğine de göz atmanızı tavsiye etmekteyim. Bu iki özellik esasında aynı davranışsal temele dayanmakta ve biz C# geliştiricilerinin icraatını zenginleştirmektedir 🙂
İlgilenenlerin faydalanması dileğiyle…
Sonraki yazılarımda görüşmek üzere…
İyi çalışmalar…

Hocam harika bir anlatım olmuş. Emeğinize sağlık. Benim gibi ingilizcesi zayıf olan kişiler için böyle içeriklere fazlasıyla ihtiyaç duyuluyor. İyi ki varsınız