· kaynak dev.to (home feed)
.NET 10, BufferedStream.WriteByte'ın sarmalanan stream'i örtük olarak flush etmesini durduruyor
.NET 10, BufferedStream.WriteByte'ın buffer dolduğunda sarmallanan stream'i flush etmesi şeklindeki uzun süredir süren tuhaflığı kaldırıyor. Bu yan etkiye güvenen kodun gerçek bir sınır noktasında açık bir flush yapması gerekiyor.

Ne değişti
Yıllar boyunca BufferedStream.WriteByte, sınıftaki diğer tüm yazma yöntemlerinden farklı davrandı: tek baytlık bir yazma, dahili buffer'ı yapılandırılmış boyutuna doldurduğunda, çağrı sarmalanan stream üzerinde Flush() metodunu çalıştırmaya devam ediyordu. dev.to'ya göre Microsoft, bu örtük flush'ın kaldırılmasını resmi bir .NET 10 davranış değişikliği olarak belgelendirdi ve yeni davranış, bir preview bayrağının arkasında değil, doğrudan .NET 10 LTS sürümünde geliyor. Yazının yazarı bunu SDK 10.0.303 ve 10.0.11 runtime ile doğrulamış; eski sözleşme için karşılaştırma 9.0.18 runtime'a karşı yapılmış.
Ayrım, "baytlar artık buffer'da kalıyor" ifadesinden daha ince. BufferedStream, daha fazla veri kabul etmek için yer açması gerektiğinde her zaman buffer'daki veriyi hedefe aktarabilirdi. .NET 10'da kaybolan şey, bu kapasite kaynaklı aktarımlara eşlik eden hedef Flush() metodu çağrısıdır. Sarmalanan stream baytları hâlâ alır; sadece aynı anda kazara bir flush artık almaz.
Yeniden üretilebilir bir fark
dev.to yazısı, bu boşluğu bir TrackingStream — Flush ve Write çağrılarını sayan bir MemoryStream alt sınıfı — ile gösteriyor; bu stream dört baytlık buffer'lı bir BufferedStream içine sarılmış. Dört baytı tek tek yazmak şunu veriyor:
- .NET 9: bir write, bir flush; hedefte 010203 bayt dizisi zaten mevcut
- .NET 10: bir write, sıfır flush; aynı üç bayt teslim edildi
Her iki runtime'da da dördüncü bayt, açık bir flush veya dispose edilene kadar BufferedStream içinde kalır; sonrasında her ikisi de tam 01020304 dizisini içerir. Yalnızca flush yan etkisi değişti. Yazar, davranışı bir stream uzunluk kontrolünden çıkarsamak yerine, tam olarak bu tür yürütülebilir bir sözleşmeyi regression testi olarak tutmayı öneriyor.
Nasıl tepki vermeli
Önerilen göç stratejisi, eski kazara zamanlamanın geri gelmesi için buffer boyutlarını ayarlamak değil. Bunun yerine, flush'ı uygulamanın gerçekten bir sınır noktasına sahip olduğu yere koyun — bir kayıt, frame veya sınırlı bir batch'ten sonra — Flush veya asenkron karşılığını kullanarak. Her bayttan sonra flush yapmak, BufferedStream'in var olma amacı olan toplu işlemeyi ortadan kaldırır.
Her kod tabanının değişmesi gerekmez. Baytların yalnızca stream dispose edildiği zamana kadar ulaşmış olması yeterliyse ve sarmalanan stream Flush()'a gözlemlenebilir bir anlam yüklemiyorsa, dispose işlemi yine son sınır noktasını sağlar. Yazı ayrıca açık bir flush'ın dayanıklılık garantisi olmadığına dikkat çekiyor: memory stream'ler, network stream'ler, sıkıştırıcılar ve dosya stream'leri Flush()'ı farklı yorumlar ve fiziksel ortamda dayanıklılık, genel bir işlem yerine depolamaya özgü işlemi gerektirir.
Flush zamanlamasına gerçekten bağlı olan ekipler için, sayan bir fake stream — ya da tam bir kaydın yalnızca seçilen flush'tan sonra görünür olduğunu doğrulayan bir protokol fixture'ı — sorunu bir ağ servisine ihtiyaç duymadan çevrimdışı yakalar.
Neden önemli
Bu değişiklik gözden kaçması kolay, çünkü uygulamalar doğru baytları üretmeye devam ediyor; kaybettikleri şey, öngörülebilir bir noktada tetiklenen bir yan etki. Bu, sarmalanan stream'in Flush'ı gözlemlenebilir kıldığı her yerde önemli: özel stream'ler, protokol adaptörleri, sıkıştırıcılar ve test double'ları. Baytlar artık hedefin kendi tamponunda veya bir sıkıştırıcının iç durumunda eskisinden daha uzun süre bekleyebilir; bu da bir eşin veya aşağı akış bileşeninin tam bir mesajı algıladığı zamanı kaydırır. Yazıdan daha geniş göç kuralı şudur: dahili buffer kapasitesini uygulama kontrol akışı olarak görmeyi bırakın ve bunun yerine protokolün veya depolama katmanının gerçekten tanımladığı sınırlarda flush edin.
- #dotnet
- #net-10
- #breaking-changes
- #streams
- #io