Tag Archives: c# 10

C# 10 Yenilikleri – Tek overload’u olan delegate türü

C# 10 ile birlikte, derleyici, yalnızca tek bir overload’a sahip olan delegate’lerin türünü çıkarabiliyor.

Örneğin;

// int
var i = Console.Read();

// Func int
Func int f = Console.Read;

Bu birden fazla overload’u olan Console.WriteLine’da çalışmaz mesela;

var str = Console.WriteLine; // Hata

Yani artık C# 10 ile şu şekilde delegate’ler yazabiliyoruz;

var str = (int i) => i.ToString();
str(42);

C# 10 Yenilikleri – CallerArgumentExpression attribute kullanımı

C# 10 ile gelen yeniliklerden biri de CallerArgumentExpression attribute kullanımı.

CallerArgumentExpression attribute kullanımı size parametre olarak verdiğiniz expression’ın string halini size geri döndürüyor. Diğer compiler servis attribute’ler gibi bu da optional.

using System.Runtime.CompilerServices;

void Write(object obj, [CallerArgumentExpression("obj")] string? msg = null)
{
    Console.WriteLine($"Expression şu: {msg}");
}

Write(new object());
Write("Merhaba");
Write(42 + 42 + 42);
Write(() lambda { });

int i = 42;
Write(i);

// Expression şu: new object()
// Expression şu: "Merhaba"
// Expression şu: 42 + 42 + 42
// Expression şu: () lambda  { }
// Expression şu: i

Kaynak: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-10.0/caller-argument-expression

C# 10 Yenilikleri – Struct ve Anonymous type’larda with kullanımı

C# 10 ile gelen yeniliklerden biri de struct ve anonymous type’larda gelen with kullanımı.

C# 9 ile hayatımıza with expression’ı girmişti. With ile solundaki operand’ın property ve field’ları ile, sağında verilen özellikler göz önüne alınarak yeni bir kopyasını oluşturur. C# 9 ile gelen with kullanımı sadece record tipi için geçerliydi.

Kısaca bir kullanım olarak;

var p1 = new Person("Soner", "İstanbul" );
// p1.Name: Soner
// p1.City: İstanbul

var p2 = p1 with { City = "Kırklareli" };
// p2.Name: Soner
// p2.City: Kırklareli

public record Person(string Name, string City);

C# 10 ile artık struct ve anonim tiplerde de with kullanımına destek gelmiş oldu. Struct için aynı kodu şu şekilde değiştirebiliriz;

var p1 = new Person();
p1.Name = "Soner";
p1.City = "İstanbul";
// p1.Name: Soner
// p1.City: İstanbul

var p2 = p1 with { City = "Kırklareli" };
// p2.Name: Soner
// p2.City: Kırklareli

public struct Person
{
    public string Name;
    public string City;
}

Anonim tiplerde de aynı şekilde kullanabiliriz;

var p1 = new { Name = "Soner", City = "İstanbul" };
// p1.Name: Soner
// p1.City: İstanbul
var p2 = p1 with { Name = "Ahmet" };
// p2.Name: Ahmet
// p2.City: İstanbul

Kaynak: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/with-expression

C# 10 Yenilikleri – Mix declarations and variables in deconstruction

C# 10 versiyonu ile gelen özelliklerden biri de “mix declarations and variables in deconstruction” kavramı.

C# 9 ve öncesi versiyonlarda deconstruction‘lar içerisinde ya hepsinin daha önceden tanımlanmış olması, ya da hepsinin yeni tanımlanıyor olması gerekiyordu.

(int, int, int) rgb = (255, 255, 0);
(int first, int second, int third) myRgb = rgb;

ya da;

int r1, g1, b1;
(r1, g1, b1) = rgb;

şeklinde tanımlanabiliyordu. C# 10 ile birlikte, bu tanımlamaların bir kısmını orada, bir kısmını ise daha öncesinde tanımlayabiliyorsunuz.

Yani;

int r2, g2;
(r2, g2, int b2) = rgb;

gibi. Gördüğünüz gibi r2 ve g2 değişkenlerimi kodumun farklı bir yerinde tanımlayıp, b2 değişkenimi deconstruction içinde tanımlayabiliyorum.

Kaynak: https://devblogs.microsoft.com/dotnet/welcome-to-csharp-10/#mix-declarations-and-variables-in-deconstruction

C# 10 Yenilikleri – File Scoped Namespaces

C# 9 ve önceki versiyonlarda Visaul Studio içerisinde yeni bir sınıf oluşturduğunuzda namespace’ler “Blocked scoped” olarak ekleniyordu. Yani namespsace’lerde süslü parantezler içerisinde ve tüm class’lar da soldan bir tab (veya 4 boşluk) olacak şekilde hizalanıyordu.

namespace NET6
{
    internal class Class1
    {
    }
}

C# 10 versiyonu ile hayatımıza File scoped namespaces kavramı girdi. Bu sayede namespace tanımlamalarındaki gereksiz süslü parantezlerden ve bu namespace’in içerisindeki her bir satır kodun başındaki gereksiz boşluklardan kurtulma imkanı sunuldu geliştiricilere. Bunun için .editorconfig dosyası içerisinde “Code Style” sekmesindeki “Namespace declarations” özelliğini “File scoped” olarak değiştirmeniz yeterli. Tabi bu değişiklik var olan sınıflarınızı etkilemiyor, yeni eklediğiniz sınıflarda geçerli.

namespace NET6;

internal class Class2
{
}

Bu videoyu çekerken aspnetcore projesinde tamamen bu yapıya geçildiğini şu commit ile görebilirsiniz. 5000’in üzerinde dosyada değişiklik yapılarak düzenleme yapılmış: https://github.com/dotnet/aspnetcore/pull/38076

Kaynak:

File Scoped Namespaces: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-10.0/file-scoped-namespaces

C# 10 Yenilikleri – Extended Property Patterns

C# 10 ile gelen küçük yeniliklerden biri de Extended Property Patterns.

C# 8 ile hayatımıza property pattern özelliği girmişti hatırlarsanız, iç içe olan property’lere süslü parantezler kullanarak erişebiliyorduk.

if (p is Person { Name: "Soner", Address: { City: "İstanbul" } })

Ama bu kullanım, bir çok iç içe property içeren yapılarda çok fazla süslü parantez olması nedeniyle okunurluğu azaltıyordu.

C# 10’da gelen extended property patterns ile, artık süslü parantez kullanmadan direkt olarak nokta notasyonu ile bu property’lere erişim sağlayabiliyoruz pattern’lar içerisinde.

if (p is Person { Name: "Soner", Address.City : "İstanbul" })

Bu yapıda da iç içe property’lerde null kontrolü var. Yani burada Address property’si null olsa bile herhangi bir nullreferenceexception fırlatmıyor.

Kaynaklar:

Extended property patterns: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-10.0/extended-property-patterns

Property Pattern: https://github.com/dotnet/csharplang/blob/main/proposals/csharp-8.0/patterns.md#property-pattern

C# 10 Yenilikleri – Constant Interpolated Strings

C# 10 ile hayatımıza yeni giren özelliklerden biri constant interpolated strings yapısı.

C# 9 ve öncesi versiyonlarda const değerler içerisinde + operatörü ile string concatenation işlemi yapabiliyorduk. Yani aşağıdaki kod legal idi;

const string Name = "";
const string  Surname = Name + " " + "Surname";

fakat şunu yapamıyorduk;

const string Name = "";
const string  Surname = $"{Name} Surname";

Bunun nedeni de string interpolation arka tarafta string.Format çağırıyordu ve bir method çağırımı compile time’da constant olamayacağı için hata veriyordu doğal olarak. Yani string interpolation içerisinde kullandığımız değer constant olsa bile, string interpolation yapısının “kendisi” constant değildi.

Bunun legal olabilmesi için C# community’den çok fazla talep gelince C# 10 versiyonunda bu özelliği de eklemişler. Bunu artık hem yukarıdaki gibi const değerleri içerisinde, hem de attribute’ler içerisinde kullandığımız mesajlarda kullanabiliyoruz.

[Obsolete($"{Name} bunu kullanamaz!")]
void MyMethod()
{
}

C# 10 Yenilikleri – Implicit Usings

.NET 6 ile hayatımıza implicit namespace kavramı girdi. Bu sayede projelerde gelen “boilerplate” içerisindeki using karmaşasından kurtulmak hedeflendi. Namespace’leri artık “global using” şeklinde projenizde tek bir .cs dosyası içerisinde veya “\..\obj\debug\net6.0” klasöründeki GlobalsUsing.cs dosyası içerisinde saklayabiliyorsunuz.

Dikkat edilmeli ki bu GlobalsUsing.cs dosyası otomatik oluşturulan bir dosya.

Örneğin projenizdeki her bir cs dosyası içerisinde System.Data namespace’ini kullanmak zorunda olduğunuzu düşünün. Her bir .cs dosyasının tepesinde bunu yazmak yerine, .csproj içerisinde ImplicitUsings tag’ini enable ederek, tek bir cs dosyası içerisinde “global using” tanımlayarak ya da bahsettiğim GlobalsUsing.cs dosyası içerisinde tanımlayarak tüm projenizde o namespace’in aktif olmasını sağlayabiliyorsunuz.

Ayrıca .csproj dosyası içerisinde ItemGroup olarak ta bu namespace’leri Using Include veya Using Remove kullanarak ekleme veya çıkartabiliyorsunuz.

RC1 ile birlikte, .NET 6 projesi oluşturduğunuzda .csproj dosyası içerisinde default olarak ImplicitUsings enable olarak geliyor. Dilerseniz bunu .csproj dosyanız içerisinde DisableImplicitNamespaceImports tag’ini true olarak disable edebiliyorsunuz.

Scott Hanselman‘ın söylediğine göre C# 10 projeleri bu sayede daha hızlı bir şekilde ayağa kalkıyorlarmış.

Her bir proje SDK tipinin default namespace değerleri şu şekilde;

Console/Library

System

System.Collections.Generic

System.IO

System.Linq

System.Net.Http

System.Threading

System.Threading.Tasks

Web

System.Net.Http.Json

Microsoft.AspNetCore.Builder

Microsoft.AspNetCore.Hosting

Microsoft.AspNetCore.Http

Microsoft.AspNetCore.Routing

Microsoft.Extensions.Configuration

Microsoft.Extensions.DependencyInjection

Microsoft.Extensions.Hosting

Microsoft.Extensions.Logging

Worker

Microsoft.Extensions.Configuration

Microsoft.Extensions.DependencyInjection

Microsoft.Extensions.Hosting Microsoft.Extensions.Logging

Kaynaklar:

Microsoft Docs: https://docs.microsoft.com/en-us/dotnet/core/compatibility/sdk/6.0/implicit-namespaces

Scott Hanselman’ın bloğu: https://www.hanselman.com/blog/implicit-usings-in-net-6