.NET 6'da Kaçırmış Olabileceğiniz 7 İyileştirme

Paylaş :

Bazen önemli olan küçük şeylerdir

.NET 6'da Kaçırmış Olabileceğiniz 7 İyileştirme

.NET 6 bu Kasım'da çıktı, birkaç üst sıra öğe tüm dikkatleri üzerine çekti. C# 10 , çalışırken yeniden yükleme, Blazor'un AOT derlemesi ve bazı ciddi iç döngü performansı iyileştirmelerinden bahsediyorum . Bunların hepsi değerli geliştirmelerdir. Ancak seçim çerçevesi öğelerinin ötesine bakarsanız, .NET 6'nın ayrıca bir dizi küçük ama akıllı iyileştirme içerdiğini görürsünüz. Bunlar, nerede bulacağınızı biliyorsanız, günlük programlamayı daha katlanılabilir kılan kolaylıklardır.

İşte favorilerim.

1. Kolay boş parametre kontrolü

Hiç kimse bir yöntemin üstüne boş parametre kontrolü yazarken sorun yaşamadı. Ancak görev o kadar sıktır ki, C# dili bile işi otomatikleştirmek için özel bir operatörle denemeler yapıyor. Bunun yerine, kodu şöyle çeviren yardımcı bir yöntem elde ettik:

public UpdateAddress(int personId, Address newAddress)
{
    if (newAddress == null)
    {
        throw new ArgumentNullException("newAddress");
    }
    ...
}

bunun içine:

public UpdateAddress(int personId, Address newAddress)
{
    ArgumentNullException.ThrowIfNull(newAddress);
    ...
}

Büyülü bir şey değil. Ancak, bir yazım hatası bekleyen büyük bir kod tabanınız olduğunda, kod okunabilirliğindeki her küçük iyileştirme önemlidir.

2. Tarihleri ve saatleri ayırma

.NET'te TimeSpan.Zero.NET'te DateTime. Ve muhtemelen zaman bilgisini "sıfırlamak" için böyle bir kod kullanmışsınızdır:

DateTime dateValue = someDateFunction(); 
DateTime dateOnly = dateValue.Date ;

Bu gayet iyi çalışıyor, ancak karşılaştırmaları ve diğer tarih hesaplamalarını karıştırabilecek zaman değerini çıkarmayı unutma şansınız her zaman vardır. Ve unutmasanız bile, başka olası uç durumlar da var. Örneğin, DateTimesaat bilgisi olmayan bir nesne ile gece yarısı 12:00'ye ayarlanmış bir nesne arasındaki farkı nasıl anlarsınız? (Kısa cevap: Yapamazsınız.)

.NET 6 sonunda bu deliği mümkün olan en basit şekilde tıkar DateOnlyTimeOnlybir DateTime. Garip isimler biraz tartışmalı olsa da, kodda kullanımları basit ve mantıklı:

// Make a DateOnly explicitly (for Jan 20, 2022)
DateOnly d1 = new DateOnly(2022, 1, 20);
// Make a DateOnly from a DateTime
DateOnly d2 = DateOnly.FromDateTime(dateValue);
// Make a TimeOnly explicitly (at 3:30 PM)
TimeOnly t1 = new TimeOnly(15, 30);
// Combine a DateOnly and a TimeOnly
DateTime dtCombined = d1.ToDateTime(t1);
// Convert a DateOnly to a DateTime (at 12:00 AM)
DateTime dtCopy = d1.ToDateTime(new TimeOnly(0,0));

Ve tabii ki, DateOnlyve TimeOnlytürleri, ile aynı temel özellikleri ve yöntemleri destekler DateTime.

Ve biz zaman ve onun birçok bilgisayar gösterimi konusu üzerindeyken, Microsoft, sizin için önemliyse, Windows ve diğer işletim sistemlerindeki saat dilimleri arasındaki uyumluluk sorunlarını gidermek için .NET 6'da biraz daha fazla çalışma yaptı.

3. Öncelik sırası oluşturma

Hepimiz StackLIFO olan koleksiyonları biliyoruz (eklenen son öğe, aldığınız ilk öğedir). Ve FIFO olan koleksiyonları biliyoruz Queue(eklenen ilk öğe, aldığınız ilk öğedir). Öncelik sıraları farklıdır — öğeler önemlerine göre alınır. Öğeyi eklediğinizde önemi atarsınız.

a'yı kullanmanın en basit yolu, PriorityQueueher öğenin önceliğini temsil eden bir tamsayı kullanmaktır. İşte bir dizi dizi içeren bir örnek:

// Fill the queue
var queue = new PriorityQueue<string, int>();
queue.Enqueue("Item with priority 2", 2);
queue.Enqueue("Item with priority 1", 1);
queue.Enqueue("Item with priority 3", 3);
// Get out all the items out
while (queue.TryDequeue(out string item, out int priority))
{
Console.WriteLine(item);
}

Bu kodu çalıştırdığınızda, önce en düşük sayısal önceliğe sahip öğeyi alırsınız. Yani sıra öncelik 1, sonra öncelik 2 ve son olarak öncelik 3 olacaktır. Öğeleri hangi sırayla eklediğiniz fark etmez.

Bir tamsayı kullanmak yerine, tarihlere (kronolojik olarak) veya dizelere (alfabetik olarak) sahip öğelere öncelik verebilirsiniz. Ancak en ilginç yaklaşım kendi IComparer. Arayüzü daha önce görmüş olabilirsiniz IComparer- örneğin, bir dizide özel sıralama uygulamak istiyorsanız onu kullanırsınız. a ile PriorityQueue, farklı öncelik kuralları tanımlamak için kullanabilirsiniz.

Yapılması IComparergereken tek şey, Compare()iki öğeyi inceleyen bir yöntemi uygulamaktır. Pozitif veya negatif bir tamsayı döndürerek hangisinin "daha büyük" veya "daha küçük" olduğunu belirtirsiniz. İşte , son tarihe göre IComparer özel bir sınıfın örneklerini nasıl sıralayacağını bilen , gerçekten basit bir örnek :ProjectStatus

public class ProjectComparer: IComparer<ProjectStatus>
{
public int Compare(ProjectStatus a, ProjectStatus b)
{
// Compare two ProjectStatus objects based on the due dates.
return a.Due.CompareTo(b.Due);
}
}
public class ProjectStatus
{
public int Status {get; set;}
public DateOnly Due {get; set;}
}

Ve şimdi bunu ProjectComparerbir : oluşturduğunuzda kullanabilirsiniz PriorityQueue:

var queue = new 
 PriorityQueue<ProjectData, ProjectStatus>(new ProjectComparer());

4. Küçük veriler için uygun şifreleme

Şifreleme, her zaman dolaylı olarak kullandığınız, ancak nadiren doğrudan kullandığınız şeylerden biridir. (Aslında, manuel şifreleme kullanmak bir kod kokusudur -  uygun bir kitaplık tarafından daha güvenli ve sağlam bir şekilde ele alınabilecek bir şeyi kendiniz yapıyor olabileceğinizin bir göstergesidir.)

Şifreleme kullanmanız gereken zamanlarda , .NET her zaman biraz garip olmuştur. Yazmak için beklediğinizden daha fazla ortak özellik var ve küçük değerleri şifreliyor olsanız bile tüm bir akış soyutlaması ile uğraşmanız gerekiyor. .NET 6'da basit durum — küçük bir veri yığınını şifrelemek — küçük bir dizi yeni yöntemle daha kolay hale gelir. İşte Aes.EncryptCbc()tek seferde tüm bir bayt bloğunu şifreleme yöntemi:

byte[] data = default;

using (Aes aes = Aes.Create())
{
aes.Key = ...
byte[] iv = ...
// One shot encryption
byte[] encrypted = aes.EncryptCbc(data, iv);
}

En azından simetrik bir şifreleme anahtarının ve başlatma vektörünün nasıl oluşturulacağını ve yönetileceğini anlamanız gerekir. Ancak verilerinizi doldurmak, dönüştürmek veya parçalamak yoktur. DecryptCbc()aynı sihri tersine çalışır.

5. Hızlı kriptografik rastgele sayılar

.NET 6, farklı algoritmalar ve karma ile şifreleme için birkaç basitleştirilmiş şifreleme yardımcı program yöntemine sahiptir (bu durumda kod tasarrufu o kadar önemli değildir). Ama RandomNumberGenerator.GetBytes()faydalı bir eklenti. Bir bayt dizisini kriptografik olarak güçlü sözde rastgele değerlerle doldurur:

byte[] randomBytes = RandomNumberGenerator.GetBytes(100)

Bu baytları gerektiği gibi başka bir veri türüne dönüştürebilirsiniz:

byte[] randomBytes = RandomNumberGenerator.GetBytes(4);
int randomInt = BitConverter.ToInt32(randomBytes);

6. LINQ ile toplama koleksiyonları

Sadık okuyucular, LINQ işlevselliği söz konusu olduğunda biraz tembel olduğumu fark etmiş olabilir. (Başka bir deyişle, bir LINQ sorgusu sorunu daha zarif bir şekilde çözebildiğinde, bazen yinelemeli mantığa düşmekten suçluyum.) Ancak bu, LINQ'nun Chunk()bize toplu taşıma için kolay bir yol sağlayan yeni uzantı yöntemini takdir etmemi engellemedi. sorgulanabilir bir koleksiyondaki öğelerin sayısı. Skip()Kibarca göz ardı ettiğim diğer geçici çözümlerden bazılarıyla mücadele ettiyseniz Take(), bu yeni sözdizimi sizi memnun edecektir:

// Let's try this out with a collection of 100 random numbers
var numbers = new List<int>();
for (int i=0; i<100; i++)
{
var rand = new Random();
numbers.Add(rand.Next(1, 100));
}
// We'll grab ten numbers at a time
var chunkSize = 10;

// Grab just one chunk
foreach(var chunk in numbers.Chunk(chunkSize))
{
Console.WriteLine("New chunk");
foreach(var item in chunk)
{
Console.WriteLine(item);
}
}

Çıktı şuna benzer:

New chunk
923
809
842
51
478
50
554
710
327
604
New chunk
996
600
373
889
433
513
494
721
339
757
New chunk
700
920
371
...

Bu kadar kolay!

7. Zaman aşımı ile asenkron bekleme

Düzenli bir .NET TaskAPI kullanıcısıysanız, uzun süren görevlerin iptali desteklemesi gerektiğini bilirsiniz, ancak bazen desteklemez. Bu sınırlamayı aşmanın birkaç yolu vardır, ancak .NET 6'da WaitAsync()yerleşik zaman aşımına sahip yararlı bir yöntem vardır. Zaman aşımı süresi dolduğunda görev tamamlanmazsa, görev devam eder, ancak kodunuz beklemeyi bırakır ve başka bir şey deneyebilir.

// Wait up to 30 seconds for this task:
await someTask.WaitAsync(TimeSpan.FromSeconds(30));

8. Ve bir bonus: Kolay paralellik

ForEachAsync()

using System.Net.Http.Headers;
using System.Net.Http.Json;
var userHandlers = new []
{
"users/okyrylchuk",
"users/shanselman",
"users/jaredpar",
"users/davidfowl"
};
using HttpClient client = new()
{
BaseAddress = new Uri("https://api.github.com"),
};
client.DefaultRequestHeaders.UserAgent.Add(
new ProductInfoHeaderValue("DotNet", "6"));
ParallelOptions parallelOptions = new()
{
MaxDegreeOfParallelism = 3
};
await Parallel.ForEachAsync(userHandlers, parallelOptions,
async (uri, token) =>
{
var user =
await client.GetFromJsonAsync<GitHubUser>(uri, token);
Console.WriteLine($"Name: {user.Name}\nBio: {user.Bio}\n");
});
public class GitHubUser
{
public string Name { get; set; }
public string Bio { get; set; }

ForEachAsync()MaxDegreeOfParallelismaynı anda gerçekleşen bir dizi görevi başlatır ( bu örnekte özellik kullanılarak bir seferde üçe kadar sıralanır ). Birbirine bağlı olmayan ayrı işlemleriniz varsa, oldukça zarif bir kod oluşturur. 

Hesabınızı yönetmek için giriş yapın

veya