Tag Archives: c#

Minimal API | Route Handler için Response çeşitleri

Minimal API içerisinde bir route handler’dan döndürülebilecek response çeşitlerini ele aldık bu videoda.

✅Github reposu: https://github.com/sonergonul/MinimalAPI

Response çeşitleri şu şekilde;

➡️ IResult – Task<IResult> veya ValueTask<IResult>

➡️ string – Task<string> veya ValueTask<string> – text/plain

➡️ T – Json seralize – application/json

🟢 app.MapGet("/response1", () lambda "Hello World");

🟢 app.MapGet("/response2", () => new { Message = "Hello World" });

🟢 app.MapGet("/response3", () => Results.Ok(new { Message = "Hello World" }));

🟢 app.MapGet("/response4", () => Results.Json(new { Message = "Hello World" }));

🟢 app.MapGet("/405", () => Results.StatusCode(405));

🟢 app.MapGet("/text", () => Results.Text("This is some text"));

🟢 app.MapGet("/old-path", () => Results.Redirect("/new-path"));

🟢 app.MapGet("/download", () => Results.File("C:/appsettings.json", contentType: "application/json", fileDownloadName: "appsettings.json"));

JIT Derleyicisine Giriş – Dizilerde sınır kontrolü

.NET içerisinde Common Language Runtime‘ın bir parçası olan JIT compiler‘ın dizilerin index sınırları konusunda yaptığı optimizasyonlara baktık bu videoda.

JIT compiler’ı bir dizi içerisinde eğer aynı branch’te (yani farklı bir kod akışına dallanma olmadan) büyük index’li kontrolü yaptıktan sonra kendisinden küçük index’ler için ayrı bir kontrol yapmasına gerek olmayacak şekilde optimizasyon yapıyor.

Yani

arr[2] = 3;

için 2 index’i için bir karşılaştırma yaptığında, bu satırdan daha sonra aynı brach’te;

arr[1] = 3;

şeklinde bir kodunuz varsa, ben zaten 2 için kontrol ettim, 2 index’li bir elemanı olan bir dizinin 1 index’li bir elemanı her zaman vardır şeklinde düşünüp burada bir karşılaştırma yapmayarak optimizasyona gidiyor.

Tabi bu optimizasyon farklı branch’lerde mevcut değil.

Videodaki kod bloğu;

 public void M(int[] arr) 
    {
        arr[0] = 1;
        arr[1] = 2;
        arr[2] = 3;
    }
    
    public void M1(int[] arr) 
    {
        arr[2] = 1;
        arr[1] = 2;
        arr[0] = 3;
    }

    public void M(int[] arr, int i) 
    {
        if(i == 1)
        {
            arr[0] = 1;
            arr[1] = 1;
        }
        else if(i == 2)
        {
            arr[0] = 1;
        }
    }

Kaynaklar:

https://sharplab.io

https://github.com/dotnet/coreclr/blob/master/src/jit/rangecheck.cpp

https://en.wikipedia.org/wiki/Branch_predictor

JIT Derleyicisine Giriş – Loop Cloning ve Loop Hoisting

.NET içerisinde Common Language Runtime‘ın bir parçası olan JIT compiler‘ın Loop cloning ve Loop Hoisting (Loop-invariant code motion olarak ta geçiyor) konularında yaptıklarına değindik bu videoda.

Kaynaklar:

https://sharplab.io/#v2:EYLgxg9gTgpgtADwGwBYA+ABATARgLABQGAzAATakDCphA3oaY6QPTOkAyEEADlQDYQAdgEtBAc1IA3GBy68AEhGEBnAC6ixDJiXIpSAWRwAKUaoDaAXVIBDKFAA0pUzcfPgAShoEmpWj59a/qQAZtAmgqpOpAC8pAAMANxRADykOHGJTgDUWe6B/vTeQf62UGbCVrHWpFmkwAn5PgC++S1FjPmssjz8QhqkgHqAtqp8toCMgPmdbAAqwrzOEHwAttZ8E+0sbABC1srCkcDCUDZQqmOA+oCkiytrU6Sp16vrARtdAAowANbCKSdQAHTsGDiVQACwA/JMNp0AFQ6DB6fRYcLmKylVwRFxOTEeLw+QrFJzBIylQHAsRgmKxOKkNBoP5kkGg+5pDJxPIbfGNYpiCCqCCkZQCADuDU5TDahO5jEktlIoKUahiNhqdTFUvFjFCUCMsuOP2pSR+qXSGSNOQ5hIJhKYpXKlXlitU6uKkuK0vIAHYXUEPUKIMKQB7tbq5Qb4kaWabMsILR7rTa/vbldVavUPW7GE0YcxCE0gA===

https://en.wikipedia.org/wiki/Loop-invariant_code_motion

https://github.com/dotnet/coreclr/blob/master/src/jit/loopcloning.cpp

Leetcode Çözümleri | Binary Tree Inorder Traversal

Leetcode içerisinde bulunan “Binary Tree Inorder Traversal” sorusunun açıklaması ve çözümü. Bu soruda size verilen bir binary tree‘nin node’larını inorder traversal, yani öncelikle rekürsif olarak sol tarafı, sonra head nodu, sonra da rekürsif olarak sağ tarafı geri döndürmeniz isteniyor.

➡️ Tree traversal: https://en.wikipedia.org/wiki/Tree_traversal

➡️ Leetcode 94. Binary Tree Inorder Traversal: https://leetcode.com/problems/binary-tree-inorder-traversal/

➡️ Problem açıklaması:

Given the root of a binary tree, return the inorder traversal of its nodes’ values.

Example 1:

Input: root = [1,null,2,3]

Output: [1,3,2]

Example 2:

Input: root = []

Output: []

Example 3:

Input: root = [1]

Output: [1]

Constraints:

The number of nodes in the tree is in the range [0, 100].

-100 <= Node.val <= 100

Follow up: Recursive solution is trivial, could you do it iteratively?

JIT Derleyicisine Giriş – Tam sayı aritmetiği

.NET içerisinde Common Language Runtime‘ın bir parçası olan JIT compiler’ın tam sayı aritmetiği konusunda yaptıklarına değindim.

JIT derleme, interpreted programların performansını iyileştirmeye yönelik bir yöntem. Runtime sırasında, performansını artırmak için program assembly kod’ta derlenebilir. Buna sürece “dinamik derleme” de deniliyor.

Bu kavram ilk olarak John McCarthy’nin 1960 yılında yayınladığı ” Recursive functions of symbolic expressions and their computation by machine, Part I” çalışmasında belirtilmiş: http://jmc.stanford.edu/articles/recursive/recursive.pdf

Ayrıca şurada da “A Brief History of Just-In-Time” şeklinde güzel bir makale var: http://eecs.ucf.edu/~dcm/Teaching/COT4810-Spring2011/Literature/JustInTimeCompilation.pdf

JIT derlemenin statik derlemeye göre bazı avantajları vardır. C# uygulamalarını çalıştırırken, “runtime” uygulama çalıştırılırken uygulamanın profilini (profiling) çıkarabilir. Bu, daha optimize edilmiş kodun oluşturulmasına izin verir. Uygulama çalışırken davranışı değişirse, runtime bu kodu yeniden derleyebilir.

Dezavantajlardan bazıları, startup gecikmeleri ve runtime sırasında derleme ek yükünü barındırmak. Ek yükü sınırlamak için birçok jit derleyicisi yalnızca sık kullanılan kod kısımlarını derler mesela.

C# içerisinde bir kodun derlenme süreci şu şekilde;

1. Derleme, sırasında kaynak kodunuzu MSIL veya IL (tam özellikli bir dildir bu arada IL fakat C#’a göre biraz daha düşük seviyede) çevirir ve gerekli meta verileri oluşturur.

2. Runtime sırasında, JIT derleyicisi, aldığı IL kodunu assembly koduna çevirir. (Kullandığı runtime ve architecture’a göre üretilen assembly kodu da değişir. Örneğin; x86, x64 veya ARM gibi). Bu nedenle .NET Runtime assembly dosyalarınızın içerisindeki IL kodunu yorumlamaz.

3. CLR, kodun çalıştırılmasını sağlayan altyapıyı ve runtime sırasında kullanılabilecek hizmetleri sağlar. Derlenmiş makine kodu, kod bölümünün bir sonraki çalıştırılışında yeniden kullanılabilecek şekilde bellekte tutulur. Bir işlevi ikinci kez çağırdığınızda, onu ilk çağırdığınızdan daha hızlı çalışacaktır çünkü ikinci kez herhangi bir JIT adımı gerekli değildir.

Bunların hepsine genel olarak “managed execution” adı verilir.

Bu arada assembly kodları içerisinde sıklıkla görebileceğiniz bazı temel cpu register’ları şu şekilde;

EAX — Değerleri toplamak için kullanılan özel bir register

ECX — Counter (döngülerde ve string’lerde kullanılır)

EDX — EAX ile birlikte kullanılan, kısa süreli değişkenleri tutan register

EBX — Data depolamak için genel bir register. Dizilerde kullanılır.

Son olarak, JIT compiler açık kaynaktır. Şu Github sayfasından inceleme yapabilirsiniz:

https://github.com/dotnet/coreclr/tree/master/src/jit

Kaynaklar:

https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/bitwise-and-shift-operators#right-shift-operator-

https://en.wikipedia.org/wiki/Logical_shift

https://en.wikipedia.org/wiki/Arithmetic_shift

https://en.wikipedia.org/wiki/X86_instruction_listings

https://en.wikipedia.org/wiki/Just-in-time_compilation

Switch içerisinde Hash Table optimizasyonu [C#]

C# compiler’ının switch statement’ı içerisinde 7. case’den sonra bir hash table optimizasyonu yaptığını biliyor muydunuz?

C# compiler’ı switch statement‘ını 6 tane case sayısına ulaşana kadar lowering mekanizması ile standart if else ifadelerine çeviriyor.

Fakat case sayısı 7’ye ulaştığında lowering mekanizması akıllıca bir optimizasyona gidiyor. Bu, C# compiler’ın işini zamanında yapmasını sağlayan çok akıllı bir optimizasyon. Bu optimizasyon, aynı string’lerin hash code’larının aynı olması gerektiği gözlemine dayanıyor. Bu yüzden string’leri teker teker eşitliğini kontrol etmek yerine, compiler hedef string’in bir hash’ini hesaplıyor table-lookup mantığında çalışmasını sağlıyor yani O(1) zamanda.

Bu Roslyn’in github sayfasında şöyle bahsedilmiş:

The string switch codegen in Roslyn is completely new. Roslyn does not use dictionaries to avoid allocations and a potentially huge penalty when a string switch is execute for the first time. Roslyn uses a private function that maps strings to hash codes and a numeric switch. In some sense this is a partial inlining of the former technic that used static dictionaries.

Kaynaklar:

https://sharplab.io/#v2:EYLgtghglgdgPgAQEwEYCwAoBBmABM3AYVwG9NcL89YAXXAWQAoEUAGXAZwEpdzKyMlIZwDuUGgGMAFo259hpeQsoSIHAKa4ARBC0h8AdlwoA3EuW5VG7cD2HcSM4Isq1mrRLsIj2Jy9fWWgAmXkYALH7+lm7a6qG4AKyR/lbuAGbxAGzJLqnaAObxBjkWQeppEACuADY0+t64ALSm5pQAvkodGG1AA=

https://en.wikipedia.org/wiki/Switch_statement#Advantages_and_disadvantages

https://github.com/dotnet/roslyn/blob/main/src/Compilers/CSharp/Portable/Compiler/MethodBodySynthesizer.Lowered.cs

C# 11 ile Gelen Yenilikler

Microsoft’un yayınladığı blog yazısına istinaden C# 11 ile gelebilecek özelliklere göz attık.

Öncelikle .NET 7 henüz long term support olmadığı için, C# 11’i kullanmak adına bazı ayarlar yapmanız gerekiyor. Bunun için visual studio 2022 17.1 versiyonunu indirmeli (community, professional veya enterprise edition fark etmez) ve .NET SDK’sının 6.0.200 versiyonunu kurmanız gerekiyor. Son olarak ta, .NET 6 ile oluşturduğunuz projenizin csproj dosyasında LangVersion tag’ını preview olarak eklemeniz gerekiyor.

✅ String interpolation’daki yenı satır kısıtı

Bildiğiniz gibi verbatim string literal‘ler içerisinde yeni satırda kullanım sağlayabiliyorduk fakat non-verbatim string literaller içerisinde bunun için \r\n kullanmamız gerekiyordu. C# 11 ile birlikte, non-verbatim interpolated string’ler için de yeni satır kısıtını kaldırmışlar.

var v = $"sayı\t: { 5.tostring()
.ToString(
Cultureınfo.InvariantCulture)}";

✅ List patterns (opsiyonel slice patterns)

Liste ve dizilerde pattern matching desteği geliyor. List pattern’lar köşeli parantezlerle belirtilirken, slice pattern’lar ise iki nokta (..) ile belirtiliyor ve isterseniz var pattern’ı da kullanabiliyorsunuz. İlerleyen zamanlarda IEnumerable tipler için de list pattern desteği getirmeyi planlıyorlarmış.

✅ Parameter null-checking (!! operatörü)

Ve geldik .NET dramasına dönen o yeniliğe. Hem Twitter hem de Github’ta çok fazla tartışıldı bu operatör. Ek olarak  @Sedat Kapanoglu  da bu yeniliği neden beğenmediğini yine aynı thread içerisinde paylaştı.

https://github.com/dotnet/csharplang/discussions/5735#discussioncomment-2153360

Özetle, C#’ta bir argümanın null kontrolü klasik olarak aşağıdaki şekildeydi;

void M1(string s)
{
   if (s is null)
   {
      throw new ArgumentNullException(nameof(s));
   }
}

.NET 6 ile ThrowiIfNull statik metodu geldi.

void M2(string s)
{
   ArgumentNullException.ThrowIfNull(nameof(s));
}

ve C# 11 ile birlikte !! (bang bang) operatörü hayatımıza girecek aynı işlevi gören.

void M3(string s!!)
{
}

Bu arada bu özellik nullable reference types ile birlikte çalışabiliyor. NRT compile time’da, parameter null-checking runtime’da kontrol şeklinde düşünebilirsiniz.

Lambda parametreleri desteği var. Indexer parametreleri için kullanılabilir. Get ve set içerisinde kontrol edilir. Constructor’lar için “field initialization”‘dan önce kontrol ediliyor. async metodlarda da kullanım mevcut.

Kaynak:

https://devblogs.microsoft.com/dotnet/early-peek-at-csharp-11-features/

https://github.com/dotnet/csharplang/discussions/5735

https://sharplab.io/#v2:EYLgtghglgdgPgAQEwEYCwAoBBmABM3AYVwG9NcL8AWXAWRQAoEUAGXAZwEpzKyNKBuKADNcDdkIkwArgBtZ3foIp9lygC4ALAE4B7AO64YAU0MBBbQHNpYYzHUA5ObICiADwDGxgA7qoumAYYCFtdYXFOTgBuHmUAX1jcBIxEgHpU3AA6BxcAFVwANkxEhBpaJCZWDkUBVTULa1t7J3l3L19/GEzcnQMASWEW2SCQ4zCI6MTkkrLsSrZ2AEJFmt4pzDigA=

Microsoft Mülakat Sorusu | Insertion Sort List

Leetcode içerisinde bulunan “Insertion Sort List” sorusunun açıklaması ve çözümü. Bu soruda size verilen linked list içerisindeki node’ları insertion sort kullanarak sıralamanız isteniyor.

➡️ Leetcode 147. Insertion Sort List: https://leetcode.com/problems/insertion-sort-list/

➡️ Problem açıklaması:

Given the head of a singly linked list, sort the list using insertion sort, and return the sorted list’s head. The steps of the insertion sort algorithm:

– Insertion sort iterates, consuming one input element each repetition and growing a sorted output list.

– At each iteration, insertion sort removes one element from the input data, finds the location it belongs within the sorted list and inserts it there.

– It repeats until no input elements remain.

The following is a graphical example of the insertion sort algorithm. The partially sorted list (black) initially contains only the first element in the list. One element (red) is removed from the input data and inserted in-place into the sorted list with each iteration.

Example 1:

Input: head = [4,2,1,3]

Output: [1,2,3,4]

Example 2:

Input: head = [-1,5,3,4,0]

Output: [-1,0,3,4,5]

Constraints:

The number of nodes in the list is in the range [1, 5000].

-5000 <= Node.val <= 5000

Minimal API | In-memory veritabanı ile CRUD işlemleri | 2. Kısım

Minimal API içinde, bir in-memory veritabanında update ve delete işlemlerini nasıl yapabileceğimizi öğrendik.

✅Github reposu: https://github.com/sonergonul/MinimalAPI

Update işlemi:

app.MapPut("/customers/{id}", async (CustomerDb db, Customer newCustomer, int id) =>
{
    var current = await db.Customers.FindAsync(id);

    if (current == null) return Results.NotFound();

    current.Name = newCustomer.Name;
    await db.SaveChangesAsync();

    return Results.NoContent();
});

Delete işlemi:

app.MapDelete("/customers/{id}", async (CustomerDb db, int id) =>
{
    var current = await db.Customers.FindAsync(id);

    if (current == null) return Results.NotFound();

    db.Customers.Remove(current);
    await db.SaveChangesAsync();

    return Results.Ok();
});

Kaynaklar:

https://docs.microsoft.com/en-us/aspnet/core/fundamentals/minimal-apis?view=aspnetcore-6.0

https://docs.microsoft.com/en-us/aspnet/core/tutorials/min-web-api?view=aspnetcore-6.0&tabs=visual-studio

Minimal API | In-memory veritabanı ile CRUD işlemleri | 1. Kısım

Minimal API ile in-memory veritabanı ile CRUD işlemlerinden listeleme ve ekleme işlemlerine baktık.

Github reposu: https://github.com/sonergonul/MinimalAPI

Bunun için Nuget içerisindeki Microsoft.EntityFrameworkCore.InMemory paketini kurduk öncelikle. Bu size in-memory olarak bir veritabanı sağlıyor. Daha sonra entity framework içerinde nasıl DbContext‘ten bir sınıf türetip içerisinde DbSet‘ler kullanarak tablolar oluşturuyorsak burada da aynı yapıyı kullanıyoruz. Sonrası aşağıdaki gibi;

Listeleme:

app.MapGet("/customers", async (CustomerDb db) => await db.Customers.ToListAsync());

Ekleme:

app.MapPost("/customers", async (CustomerDb db, Customer cus) => 
{
    await db.Customers.AddAsync(cus);
    await db.SaveChangesAsync();
    return Results.Created($"/customers/{cus.Id}", cus);
});

ID bazlı listeleme:

app.MapGet("/customers/{id}", async (CustomerDb db, int id) => await db.Customers.FindAsync(id));

Kaynaklar:

https://docs.microsoft.com/en-us/aspnet/core/tutorials/min-web-api?view=aspnetcore-6.0&tabs=visual-studio

https://docs.microsoft.com/en-us/aspnet/core/fundamentals/minimal-apis?view=aspnetcore-6.0