Category Archives: .NET

.NET 6 Yenilikleri – Nuget paket validasyonu

.NET 6 ile gelen yeniliklerden biri de EnablePackageValidation kullanımı.

Bu tag nuget paketlerinizin validasyonunun sağlıyor. Peki ne bu validasyonlar?

  • Sürümler arasında birbirini bozan değişiklik olup olmadığını doğrular.
  • Paketin, farklı runtime implementasyonlarına özgü uygulamalar için aynı public API yapısına sahip olup olmadığını doğrular.
  • Geliştiricilerin uygulanabilirlik açıklarını yakalamasına yardımcı olur.

Projenizin .csproj dosyası içerisinde PropertyGroup altında kullanabilirsiniz bu tag’ı.

<PropertyGroup>
  <EnablePackageValidation>true</EnablePackageValidation>
</PropertyGroup>

Kaynak:

https://docs.microsoft.com/en-us/dotnet/fundamentals/package-validation/overview

.NET 6 Yenilikleri – IANA Time zone desteği

.NET 6 ile gelen yeniliklerden biri de Windows time zone desteğine ilave olarak IANA time zone desteğinin geldi.

.NET 6 ile birlikte bütün platform’larda Windows time zone desteğine ek olarak IANA time zone desteği geldi. Bildiğiniz gibi günümüzde IANA time zone en güncel ve en popüler zaman dili bilgisine sahip yapılardan biri. Bu nedenle bu desteğin gelmesi geliştiriciler için gayet faydalı oldu.

Aşağıdaki kod parçasına bir göz atalım;

var ianaZoneId = "Europe/Istanbul";

var zoneInfo = TimeZoneInfo.FindSystemTimeZoneById(ianaZoneId);
Console.WriteLine(zoneInfo.DisplayName);
// (UTC+03:00) Istanbul

TimeZoneInfo.TryConvertIanaIdToWindowsId(ianaZoneId, out var windowsId);
Console.WriteLine(windowsId);
// Turkey Standard Time

TimeZoneInfo.TryConvertWindowsIdToIanaId(windowsId, out ianaZoneId);
Console.WriteLine(ianaZoneId);
// Europe/Istanbul

Console.WriteLine(zoneInfo.HasIanaId); // True

.NET 5 ve öncesinde yukarıdaki FindSystemTimeZoneById metodu TimeZoneNotFoundException fırlatırdı “Europe/Istanbul” için. Ama artık .NET 6 ile birlikte bu destek sağlanmış oldu.

TryConvertIanaIdToWindowsId ve TryConvertWindowsIdToIanaId statik metodları ile de windows time zone id’den iana time zone id’ye çevirme ve tam tersi işlemi yapabiliyoruz.

HasIanaId property’si ile de TimeZoneInfo instance’ının bir IANA id karşılığı olup olmadığını görebiliyoruz.

IANA time zone resmi sitesi: https://www.iana.org/time-zones

.NET 6 Yenilikleri – LINQ *OrDefault metodlarında default değerler

.NET 6 ile gelen yeniliklerden biri de LINQ içerisindeki *OrDefault metodlarında default değer atanma özelliği.

.NET 5 ve öncesinde IEnumerable içerisinde bulunan First, Last ve Single metodları aldıkları predicate’e göre herhangi bir eleman bulunamazsa InvalidOperationException fırlatıyorlardı.

Yani;

var list = new List int  { 1, 2, 3};

var first = list.First(i => i > 3); // InvalidOperationException
var last = list.Last(i => i > 3); // InvalidOperationException
var single = list.Single(i => i > 3); // InvalidOperationException

.NET 6 ile birlikte bu metodlara ek olarak FirstOrDefault, LastOrDefault ve SingleOrDefault metodlarına default değer atama özelliği geldi. Bunlar aldıkları predicate’e göre eğer bir eleman bulunamazsa defaultValue ile verdiğiniz değeri geri döndürüyorlar.

first = list.FirstOrDefault(i => i > 3, -1);
last = list.LastOrDefault(i => i > 3, -2);
single = list.SingleOrDefault(i => i > 3, -3);

Console.WriteLine($"{first} {last} {single}");
// -1 -2 -3

Kaynak: Announcing .NET 6 — The Fastest .NET Yet

https://devblogs.microsoft.com/dotnet/announcing-net-6/#system-linq-firstordefault-lastordefault-singleordefault-overloads-taking-default-parameters

.NET 6 Yenilikleri – Chunk ile collection’ları eşit parçalara ayırma

.NET 6 ile birlikte hayatımıza giren yeniliklerden biri de IEnumerable.Chunk metodu.

.NET 5 ve öncesinde, collection’ları eşit sayıda elemanlar olacak şekilde parçalara ayırmak için 2 yöntem vardı.

Birincisi aşağıdaki gibi bir custom (veya extension) metod yazmak;

static List List T Split T (IList T source, int size)
{
    return source.Select((x, i) = new { Index = i, Value = x })
        .GroupBy(x => x.Index / size)
        .Select(x => x.Select(v = v.Value).ToList())
        .ToList();
}

İkincisi de MoreLINQ içerisinde bulunan Batch metodunu kullanmaktı.

var buckets = numbers.Batch(10);

.NET 6 ile gelen IEnumerable.Chunk metodu ile bu işlemi artık custom bir metoda veya bir nuget paketine ihtiyaç duymadan halledebiliyoruz.

IEnumerable int numbers = Enumerable.Range(1, 34);
IEnumerable int[] buckets = numbers.Chunk(10);

foreach (int[] bucket in buckets)
{
    Console.WriteLine($"{bucket.First()} {bucket.Last()}");
}

Sonuç:

1 10
11 20
21 30
31 34

Kaynak: https://docs.microsoft.com/en-us/dotnet/api/system.linq.enumerable.chunk

.NET 6 Yenilikleri – Enumerable içerisinde *By metodları

.NET 6 ile gelen yeniliklerden biri de Enumerable içerisinde gelen *By extension metodları.

.NET 5 ve öncesi, tanımladığımız custom bir yapı için compare kısmını yaparken o yapıyı IComparable interface’inden türetip CompareTo metodunu kullanıyorduk klasik bir şekilde.

Örneğin;

record Product : IComparable
{
    public string Name { get; set; }
    public decimal Price { get; set; }
    public int CompareTo(object obj)
    {
        var person = (Product)obj;
        return decimal.Compare(Price, person.Price);
    }
}

Bu şekilde yaptığımız için karşılaştırma yapan metodları bu custom yapı için kullanabiliyorduk.

var products = new List of Product ();
products.Add(new Product { Name = "P1", Price = 15 });
products.Add(new Product { Name = "P2", Price = 5 });
products.Add(new Product { Name = "P3", Price = 25 });

var cheapest = products.Min();
Console.WriteLine(cheapest); // Product { Name = P2, Price = 5 }

var mostExpensive = products.Max();
Console.WriteLine(mostExpensive); // Product { Name = P3, Price = 25 }

Bu *By metodları ile, artık parametre verdiğimiz “keySelector” ile hangi özelliğe göre karşılaştırma yapılacağını belirtebiliyoruz. Bu nedenle bu custom yapıyı IComparable interface’inden türetmeye, doğal olarak ta CompareTo metodunu yazmamıza ihtiyacımız kalmıyor.

var cheapest = products.MinBy(p => p.Price);
var mostExpensive = products.Max(p => p.Price);

.NET 6 ile hayatımıza giren yeni metodlar şunlar; MaxBy, MinBy, DistinctBy, UnionBy, IntersectBy ve ExceptBy.

Kaynak: Announcing .NET 6 — The Fastest .NET Yet

https://devblogs.microsoft.com/dotnet/announcing-net-6/#system-linq-distinctby-unionby-intersectby-exceptby

.NET 6 Yenilikleri – ThrowIfNull ile null kontrolü

.NET 5 ve öncesinde, bir metod içerisinde argümanın null kontrolünü yapmak için kullandığımız klasik yöntem şu şekildeydi;

void MyMethod(object obj)
{
   if (obj is null)
   {
      throw new ArgumentNullException(nameof(obj));
   }
}

.NET 6 ile bunu daha kolay bir şekilde yapabilmemiz için statik bir ThrowIfNull metodu eklenmiş. İşlevsel olarak tamamen yukarıdaki kullanımla aynı mantıkta çalışıyor. Daha kısa ve sade bir kullanım.

void MyMethod(object obj)
{
   ArgumentNullException.ThrowIfNull(obj);
}

Kaynak: ArgumentNullException.ThrowIfNull(Object, String) Method

https://docs.microsoft.com/en-us/dotnet/api/system.argumentnullexception.throwifnull?view=net-6.0

.NET 6 Yenilikleri – DateOnly ve TimeOnly

Eğer .NET Framework ile aşinaysanız, DateTime ve DateTimeOffset gibi yapıları daha önce kullanmışsınızdır.

.NET 6 ile hayatımıza 2 yeni struct girdi: DateOnly ve TimeOnly.

DateOnly isimden de anlaşılacağı gibi “”sadece tarih” değerini barındırıyor. Bu yapı doğum günleri, işe alım tarihi, iş günleri gibi, belirli bir zaman ile ilişkisi olmayan birimler için gayet uygun bir yapı. Bu yapı tabi o tarih gününün “tamamını” kapsıyor şeklinde düşünebilirsiniz. Özellikle TimeZoneInfo gibi bir yapı içerisinde belki de o timezone için var olmayan bir saat değerine sahip bir DateTime’ı çevirirken oluşabilecek olası bug’ların da bu yapı sayesinde önüne geçiliyor.

DateTime gibi Kind özelliği yok DateOnly içerisinde, her zaman Unspecified olarak düşünebilrisiniz.

Sql Server vb. veritabanları ile iletişimde olduğunda da DateOnly yapısı gayet kullanışlı çünkü bir çok veritabanında var olan “date” yapısıyla gayet uyumlu. DateTime’ı bu tip ile eşleştirdiğinizde zaman özelliğini kaybediyordunuz, bu senaryoda en azından artık bir “zaman” olmadığını düşünebiliyoruz.

DateTime gibi 0001-01-01 ile 9999-12-31 aralığında. Ve yine DateTime gibi internal olarak gregoryan takviminde her zaman constructor içerisinde başka Calendar verseniz bile.

TimeOnly de isimden anlaşılacağı gibi, sadece günün saatini tutan bir struct. Bu yapı görüşme saati, günlük alarm saati gibi sadece saatin önemli olduğu kavramlar için gayet uygun.

TimeSpan gibi bir zaman aralığı değil de, gece yarısından itibaren geçen zaman’ı tutuyor bu. Aralığı 00:00:00.0000000 ile 23:59:59.9999999. DateTime gibi Ticks bazlı bir yapısı var (gece yarısından itibaren). TimeSpan gibi negatif olamıyor. TimeSpan’i günün saati olarak parse ederken sorunlar çıkabiliyordu, TimeOnly’de böyle bir risk yok.

Son olarak, TimeOnly’nin InBetween metodu çok güzel. Hem normal saat aralıkları için (10:00 ile 12:00 arasında mı), hem de gece yarısını geçen case’lerde (23:00 ile 02:00 arasında mı) çalışıyor.

Kaynaklar:

DateOnly MSDN: https://docs.microsoft.com/en-us/dotnet/api/system.dateonly?view=net-6.0

TimeOnly MSDN: https://docs.microsoft.com/en-us/dotnet/api/system.timeonly?view=net-6.0

Date, Time, and Time Zone Enhancements in .NET 6: https://devblogs.microsoft.com/dotnet/date-time-and-time-zone-enhancements-in-net-6/

.NET 6 Yenilikleri – IsPow2 ve RoundUpToPowerOf2

.NET 6 ile hayatımıza BitOperations sınıfı içerisinde 2 yeni metod girdi. BitOperations sınıfı genellikle bit manipülasyonları için kullanılan statik bir utility sınıfı.

Bu operasyonlar;

✔️IsPow2: Verilen bir int yada long değerinin 2’nin bir tam sayı kuvveti olup olmadığını döndürür.

Console.WriteLine(BitOperations.IsPow2(64)); /// true 

https://source.dot.net/#System.Private.CoreLib/BitOperations.cs,49

✔️RoundUpToPowerOf2: Verilen bir int ya da long değerinden büyük ya da eşit, en küçük 2’nin tam sayı kuvvetini döndürür.

Console.WriteLine(BitOperations.RoundUpToPowerOf2(100)); /// 128 

https://source.dot.net/#System.Private.CoreLib/BitOperations.cs,97

Videoda bahsettiğim, Leetcode içerisindeki Amazon mülakat sorusu Power of Two: https://youtu.be/wi5jAQozZQA