Not
Bu sayfaya erişim yetkilendirme gerektiriyor. Oturum açmayı veya dizinleri değiştirmeyi deneyebilirsiniz.
Bu sayfaya erişim yetkilendirme gerektiriyor. Dizinleri değiştirmeyi deneyebilirsiniz.
Not
Bu makale bir özellik belirtimidir. Belirtim, özelliğin tasarım belgesi olarak görev alır. Önerilen belirtim değişikliklerini ve özelliğin tasarımı ve geliştirilmesi sırasında gereken bilgileri içerir. Bu makaleler, önerilen belirtim değişiklikleri son haline getirilene ve geçerli ECMA belirtimine dahil edilene kadar yayımlanır.
Özellik belirtimi ile tamamlanan uygulama arasında bazı tutarsızlıklar olabilir. Bu farklılıklar, ilgili dil tasarım toplantısı (LDM) notlarında kaydedilir.
Özellik belirtimlerini C# dil standardına benimseme işlemi hakkında daha fazla bilgi edinmek için
Şampiyon sorunu: https://github.com/dotnet/csharplang/issues/184
Özet
Bu teklif, C# dilinde UTF8 dize değişmez değerleri yazma özelliğini ekler ve bunların utf-8 byte gösterimine otomatik olarak kodlanmış olmasını sağlar.
Motivasyon
UTF8, web'in dilidir ve .NET yığınının önemli bölümlerinde kullanılması gerekir. Verilerin çoğu ağ yığınından byte[] biçiminde gelse de kodda sabitlerin önemli kullanımları vardır. Örneğin ağ yığınının genellikle "HTTP/1.0\r\n", " AUTH" veya gibi sabitler yazması gerekir.
"Content-Length: ".
Bugün, C# UTF16 kodlaması kullanan tüm dizeleri temsil ettiği için bunu yapmak için etkili bir söz dizimi yoktur. Bu, geliştiricilerin başlangıçta gerçekten kodlama işlemini gerçekleştirmesi (ve gerçekten bunları gerektirmeyen bir türü hedeflemesi durumunda ayırmalar) veya baytları el ile çevirip bir byte[]içinde depolama dahil olmak üzere ek yük oluşturan çalışma zamanında kodlama kolaylığı arasında seçim yapmaları gerekmesi anlamına gelir.
// Efficient but verbose and error prone
static ReadOnlySpan<byte> AuthWithTrailingSpace => new byte[] { 0x41, 0x55, 0x54, 0x48, 0x20 };
WriteBytes(AuthWithTrailingSpace);
// Incurs allocation and startup costs performing an encoding that could have been done at compile-time
static readonly byte[] s_authWithTrailingSpace = Encoding.UTF8.GetBytes("AUTH ");
WriteBytes(s_authWithTrailingSpace);
// Simplest / most convenient but terribly inefficient
WriteBytes(Encoding.UTF8.GetBytes("AUTH "));
Bu ödün, çalışma zamanı, ASP.NET ve Azure'daki iş ortaklarımız için sıkça karşılaşılan bir sorun teşkil etmektedir. Çoğu zaman, byte[] kodlamasını el ile yazma zahmetine girmek istemedikleri için performanslarını tabloda bırakmalarına neden olur.
Bunu düzeltmek için, dilde UTF8 sabitlerini destekleyecek ve bunları derleme zamanında UTF8 byte[]'a kodlayacağız.
Ayrıntılı tasarım
Dize değişmez değerlerine u8 soneki
Dil, türü UTF8 olarak zorlamak için dize sabitlerine u8 son ekini ekler.
Sonek büyük/küçük harfe duyarsızdır, U8 sonek desteklenecek ve u8 soneki ile aynı anlama gelecektir.
u8 soneki kullanıldığında, literal değeri dizenin UTF-8 bayt gösterimini içeren bir ReadOnlySpan<byte> olur.
Bellekteki son bayttan (ve ReadOnlySpan<byte>uzunluğunun dışında) sonraya, null sonlandırıcı yerleştirilir. Bu, çağrının null sonlandırılmış dizeler beklediği bazı etkileşim senaryolarını ele almak içindir.
string s1 = "hello"u8; // Error
var s2 = "hello"u8; // Okay and type is ReadOnlySpan<byte>
ReadOnlySpan<byte> s3 = "hello"u8; // Okay.
byte[] s4 = "hello"u8; // Error - Cannot implicitly convert type 'System.ReadOnlySpan<byte>' to 'byte[]'.
byte[] s5 = "hello"u8.ToArray(); // Okay.
Span<byte> s6 = "hello"u8; // Error - Cannot implicitly convert type 'System.ReadOnlySpan<byte>' to 'System.Span<byte>'.
Değişmez değerler genel sabitler olarak ayrılacağı için, sonuçta elde edilen ReadOnlySpan<byte>'ın ömür süresi, döndürülmesini veya başka yerlere iletilmesini engellemez. Ancak, belirli bağlamlar, özellikle zaman uyumsuz işlevlerde, ref yapısı türlerinin yerel değişkenlerine izin vermez, bu nedenle bu durumlarda bir ToArray() çağrısı veya benzer bir çağrının gerekmesiyle kullanımda bir ceza söz konusu olur.
u8 metinsel terimi sabit bir değere sahip olmaz. Bunun nedeni ReadOnlySpan<byte>'ın bugün sabit türü olamamasıdır.
const tanımı gelecekte ReadOnlySpan<byte>göz önünde bulundurulacak şekilde genişletilirse, bu değer de sabit olarak kabul edilmelidir. Pratikte bu, u8 değişmez değerinin isteğe bağlı bir parametrenin varsayılan değeri olarak kullanılamayacağı anlamına gelir.
// Error: The argument is not constant
void Write(ReadOnlySpan<byte> message = "missing"u8) { ... }
Değişmez değerin giriş metni hatalı biçimlendirilmiş bir UTF16 dizesi olduğunda, dil bir hata gösterir:
var bytes = "hello \uD8\uD8"u8; // Error: malformed UTF16 input string
var bytes2 = "hello \uD801\uD802"u8; // Allowed: invalid UTF16 values, but it's correctly formed.
Toplama işleci
aşağıda gösterildiği gibi §12.10.5 Toplama işlecine yeni bir madde işareti eklenecektir.
UTF-8 bayt dizisinin birleştirilmesi:
ReadOnlySpan<byte> operator +(ReadOnlySpan<byte> x, ReadOnlySpan<byte> y);Bu ikili
+işleci bayt dizilerini birleştirme işlemi gerçekleştirir ve yalnızca her iki işlenenin de semantik olarak UTF-8 bayt gösterimi olması durumunda geçerlidir.u8değişmez değerinin bir değeri veya UTF8 bayt gösterimi birleştirme operatörünün ürettiği bir değer olduğunda, işlenen semantik olarak bir UTF8 bayt gösterimidir.UTF8 bayt gösterimi birleştirildiğinde elde edilen sonuç, sol işlenenin baytları ve ardından sağ işlenenin baytlarından oluşan bir
ReadOnlySpan<byte>'dır. Bellekteki son bayttan (veReadOnlySpan<byte>uzunluğunun dışında) sonraya, null sonlandırıcı yerleştirilir. Bu, çağrının null sonlandırılmış dizeler beklediği bazı etkileşim senaryolarını ele almak içindir.
Düşürme
Dil, geliştiricinin kodda elde edilen byte[] sabitini yazdığı gibi, UTF8 kodlanmış dizelerini tam olarak küçültür. Mesela:
ReadOnlySpan<byte> span = "hello"u8;
// Equivalent to
ReadOnlySpan<byte> span = new ReadOnlySpan<byte>(new byte[] { 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x00 }).
Slice(0,5); // The `Slice` call will be optimized away by the compiler.
Bu, new byte[] { ... } formuna uygulanan tüm iyileştirmelerin utf8 değişmez değerlerine de uygulanacağı anlamına gelir. Bu, C# bunu PE dosyasının .data bölümünde depolanacak şekilde optimize edeceği için çağrı noktasının bellek ayırımı gerektirmeyeceği anlamına gelir.
UTF8 bayt gösterimi birleştirme işleçlerinin ardışık birden çok uygulaması, son bayt dizisini içeren bayt dizisiyle tek bir ReadOnlySpan<byte> oluşturma işlemine daraltılır.
ReadOnlySpan<byte> span = "h"u8 + "el"u8 + "lo"u8;
// Equivalent to
ReadOnlySpan<byte> span = new ReadOnlySpan<byte>(new byte[] { 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x00 }).
Slice(0,5); // The `Slice` call will be optimized away by the compiler.
Dezavantaj -ları
Temel API'lere güvenme
Derleyici uygulaması hem geçersiz dize algılama hem de UTF8Encodingçevirisi için byte[] kullanır. Tam API'ler büyük olasılıkla derleyicinin hangi hedef çerçeveyi kullandığına bağlıdır. Ancak UTF8Encoding uygulamanın iş atı olacaktır.
Derleyici geçmişte değişmez değer işleme için çalışma zamanı API'lerini kullanmaktan kaçınmıştır. Bunun nedeni, sabitlerin dilden ve çalışma zamanına nasıl işlendiğinin denetimini almasıdır. Somut olarak bu, hata düzeltmeleri gibi öğelerin sabit kodlamayı değiştirebileceği ve C# derlemesinin sonucunun derleyicinin hangi çalışma zamanında çalıştırıldığına bağlı olduğu anlamına gelir.
Bu varsayımsal bir sorun değil. Roslyn'in ilk sürümleri kayan nokta sabit ayrıştırma işlemini işlemek için double.Parse kullanıyordu. Bu da bir dizi soruna neden oldu. İlk olarak, bazı kayan nokta değerlerinin yerel derleyici ile Roslyn arasında farklı gösterimleri olduğu anlamına geliyordu. İkincisi, .NET Core'un double.Parse kodundaki uzun süreli hataları geliştirmesi ve düzeltmesi, bu sabitlerin anlamının derleyicinin hangi çalışma zamanında çalıştırıldığına bağlı olarak dilde değiştiği anlamına geliyordu. Sonuç olarak derleyici, kayan nokta ayrıştırma kodunun kendi sürümünü yazmaya ve double.Parsebağımlılığını kaldırmaya son verdi.
Bu senaryo çalışma zamanı ekibiyle görüşüldü ve daha önce karşılaştığımız aynı sorunların olmadığını düşünüyoruz. UTF8 ayrıştırma, çalışma zamanları arasında kararlıdır ve bu alanda gelecekte uyumluluk sorunlarına yol açabilecek bilinen bir sorun mevcut değildir. Eğer biri ortaya çıkarsa stratejiyi yeniden değerlendirebiliriz.
Alternatif
Yalnızca hedef türü
Tasarım yalnızca hedef yazmayı kullanabilir ve u8 değişmez değerlerde string sonekini kaldırabilir. Günümüzde çoğu durumda, string sabitinin doğrudan bir ReadOnlySpan<byte>'e atanması nedeniyle gereksiz hale gelmiştir.
ReadOnlySpan<byte> span = "Hello World;"
u8 soneki öncelikli olarak iki senaryoyu desteklemek için vardır: var ve aşırı yükleme çözümü. İkincisi için aşağıdaki kullanım örneğini göz önünde bulundurun:
void Write(ReadOnlySpan<byte> span) { ... }
void Write(string s) {
var bytes = Encoding.UTF8.GetBytes(s);
Write(bytes.AsSpan());
}
Uygulama dikkate alındığında, Write(ReadOnlySpan<byte>) çağırmak daha iyidir ve u8 eki bunu kolaylaştırır: Write("hello"u8). Geliştiricilerin Write((ReadOnlySpan<byte>)"hello")garip atamalara başvurması gerekmemesi.
Yine de bu isteğe bağlı bir özelliktir, özellik bu olmadan da çalışabilir ve ileride eklemek sorun yaratmaz.
Utf8String türünü bekleyin
.NET ekosistemi bugün defacto Utf8 dize türü olarak ReadOnlySpan<byte> standartlaşırken, çalışma zamanının gelecekte gerçek bir Utf8String türü getirmesi mümkündür.
Bu olası değişiklik karşısında buradaki tasarımımızı değerlendirmeli ve aldığımız kararlardan pişman olup olmayacağımızı yansıtmalıyız. Bu, kabul edilebilir bir alternatif olarak Utf8String bulduğumuz her gün azalmış gibi görünen bir olasılık olan ReadOnlySpan<byte>tanıtacağımız gerçekçi olasılığa karşı tartılmalıdır.
Dize değişmez değerleri ile ReadOnlySpan<byte>arasındaki hedef tür dönüştürmesine pişmanlık duymamız pek olası görünmüyor. utf8 olarak ReadOnlySpan<byte> kullanımı api'lerimize eklendiğinden, Utf8String ortaya çıksa ve "daha iyi" bir tür olsa bile dönüştürmede hala değer vardır. Programlama dili, basitçe, Utf8Stringyerine ReadOnlySpan<byte> dönüştürmelerini tercih edebilir.
u8 sonekinin ReadOnlySpan<byte>yerine Utf8String işaret etmesine pişman olma olasılığımız daha muhtemel görünüyor.
stackalloc int[]'nin int*yerine doğal bir Span<int> türüne sahip olmasından duyduğumuz pişmanlığa benzer. Bu bir sorun yaratmaz, sadece can sıkıcı bir durum.
string sabitleri ile byte dizileri arasındaki dönüştürmeler
Bu bölümdeki dönüştürmeler uygulanmadı. Bu dönüştürmeler etkin teklifler olmaya devam eder.
Dil, metnin eşdeğer UTF8 bayt gösterimine dönüştürüldüğü string sabitler ile byte dizileri arasında dönüştürmelere izin verir. Özellikle derleyici, string_constant_to_UTF8_byte_representation_conversion - string sabitlerinden byte[], Span<byte>ve ReadOnlySpan<byte>'e doğru örtük dönüştürmelere izin verir.
Örtük dönüştürmeler bölümünün §10.2 kısmına yeni bir madde işareti eklenecek. Bu dönüştürme , §10.4 vestandart bir dönüştürme değildir.
byte[] array = "hello"; // new byte[] { 0x68, 0x65, 0x6c, 0x6c, 0x6f }
Span<byte> span = "dog"; // new byte[] { 0x64, 0x6f, 0x67 }
ReadOnlySpan<byte> span = "cat"; // new byte[] { 0x63, 0x61, 0x74 }
Dönüştürme için giriş metni hatalı biçimlendirilmiş bir UTF16 dizesi olduğunda, dil bir hata gösterir:
const string text = "hello \uD801\uD802";
byte[] bytes = text; // Error: the input string is not valid UTF16
Bu özelliğin başlıca kullanımının literallerle olması beklenir, ancak herhangi bir string sabit değerle de çalışır.
string değere sahip bir null sabitinden dönüştürme de desteklenir. Dönüştürmenin sonucu hedef türün default değeri olacaktır.
const string data = "dog"
ReadOnlySpan<byte> span = data; // new byte[] { 0x64, 0x6f, 0x67 }
Dizelerde +gibi herhangi bir sabit işlem söz konusu olduğunda, UTF8 kodlaması, her bir parçanın işlenip sonuçların birleştirilmesinden ziyade, nihai string üzerinde gerçekleştirilir. Dönüştürmenin başarılı olup olmadığını etkileyebileceğinden bu sıralamanın dikkate alınması önemlidir.
const string first = "\uD83D"; // high surrogate
const string second = "\uDE00"; // low surrogate
ReadOnlySpan<byte> span = first + second;
Buradaki iki bölüm, vekil çiftin tamamlanmamış bölümleri olduğundan kendi başlarına geçersizdir. Tek tek UTF8'e doğru çeviri yoktur, ancak birlikte UTF8'e başarıyla çevrilebilen eksiksiz bir vekil çift oluştururlar.
Linq İfade Ağaçlarında string_constant_to_UTF8_byte_representation_conversion'e izin verilmiyor.
Bu dönüştürmelere yönelik girişler sabitler olsa ve veriler derleme zamanında tamamen kodlanmış olsa da, dönüştürme dil tarafından sabit olarak kabul değildir. Bunun nedeni dizilerin günümüzde sabit olmamasıdır.
const tanımı gelecekte dizileri dikkate almak için genişletilirse, bu dönüştürmeler de göz önünde bulundurulmalıdır. Pratikte bu, bu dönüştürmelerin sonucunun isteğe bağlı bir parametrenin varsayılan değeri olarak kullanılamayacağı anlamına gelir.
// Error: The argument is not constant
void Write(ReadOnlySpan<byte> message = "missing") { ... }
Uygulanan dize değişmez değerleri, dildeki diğer değişmez değerlerle aynı soruna sahip olacak: temsil ettikleri tür, nasıl kullanıldıklarına bağlıdır. C# diğer değişmez değerlerin anlamını belirsiz hale getirmek için bir değişmez değer son eki sağlar. Örneğin geliştiriciler, değeri 3.14f veya float1lolmaya zorlamak için long yazabilir.
Çözülmemiş sorular
İlk üç tasarım sorusu, dize ile Span<byte> / ReadOnlySpan<byte> dönüştürmeleri arasında ilişki kurar. Henüz uygulanmadılar.
(Çözüldü) string sabiti ile null değeri ve byte dizileri arasındaki dönüştürmeler
Bu dönüştürmenin desteklenip desteklenmediği ve destekleniyorsa nasıl gerçekleştirildiği belirtilmez.
Teklifi:
string değerine sahip bir null sabitinden byte[], Span<byte>ve ReadOnlySpan<byte>'e örtük dönüşümlere izin verin. Dönüştürmenin sonucu hedef türün default değeridir.
Çözümleme:
Teklif onaylandı - https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-01-26.md#conversions-from-null-literals.
(Çözüldü) string_constant_to_UTF8_byte_representation_conversion nereye ait?
Teklifi:
"Örtük ilişkilendirmeli dize dönüştürmeleri" veya "Yöntem grubu dönüştürmeleri" gibi, örtük dönüştürmelerde §10.2yeni bir madde işaretidir. "Kaynak sabit bir ifade olsa da sonuç hiçbir zaman sabit bir ifade olmadığından, 'Örtük sabit ifade dönüştürmeleri'ne aitmiş gibi gelmez." Ayrıca , "Örtük sabit ifade dönüştürmeleri", kullanıcı tanımlı dönüştürmeleri içeren önemsiz olmayan davranış değişikliklerine yol açabilecek olan §10.4.2
Çözümleme:
Dize sabitini UTF-8 baytlarına dönüştürmek için yeni bir tür tanıtacağız - https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-01-26.md#conversion-kinds
(Çözüldü) string_constant_to_UTF8_byte_representation_conversion standart bir dönüştürme mi?
"Saf" Standart Dönüştürmelere (standart dönüştürmeler, kullanıcı tanımlı dönüştürmenin parçası olarak gerçekleşebilen önceden tanımlanmış dönüştürmelerdir) ek olarak, derleyici önceden tanımlanmış bazı dönüştürmeleri de "biraz" standart olarak ele alır. Örneğin, koddaki hedef türe açık bir dönüşüm varsa, örtük bir interpolasyonlu dize dönüştürmesi kullanıcı tanımlı bir dönüşümün parçası olarak gerçekleşebilir. Standart örtük veya açık dönüştürme kümesine açıkça dahil edilmeyen bir örtük dönüştürme olmasına rağmen, Standart Açık Dönüştürme gibi değerlendiriliyor. Mesela:
class C
{
static void Main()
{
C1 x = $"hello"; // error CS0266: Cannot implicitly convert type 'string' to 'C1'. An explicit conversion exists (are you missing a cast?)
var y = (C1)$"dog"; // works
}
}
class C1
{
public static implicit operator C1(System.FormattableString x) => new C1();
}
Teklifi:
Yeni dönüştürme standart bir dönüştürme değildir. Bu, kullanıcı tanımlı dönüştürmeleri içeren önemsiz olmayan davranış değişikliklerini önler. Örneğin, örtük demet sabiti dönüşümleri vb. altında kullanıcı tanımlı dönüşümler konusunda endişelenmemiz gerekmez.
Çözümleme:
Şimdilik standart bir dönüştürme değil - https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-01-26.md#implicit-standard-conversion.
(Çözüldü) Linq İfade Ağacı dönüşümü
Linq İfade Ağacı dönüştürme bağlamında string_constant_to_UTF8_byte_representation_conversion'e izin verilsin mi? Şimdilik buna izin vermeyebiliriz veya sadece "alçaltılmış" formu ağaca ekleyebiliriz. Mesela:
Expression<Func<byte[]>> x = () => "hello"; // () => new [] {104, 101, 108, 108, 111}
Expression<FuncSpanOfByte> y = () => "dog"; // () => new Span`1(new [] {100, 111, 103})
Expression<FuncReadOnlySpanOfByte> z = () => "cat"; // () => new ReadOnlySpan`1(new [] {99, 97, 116})
u8 ile dize değişmez değerleri ne olacak? Bunları bayt dizisi oluşturmaları olarak ortaya çıkarabiliriz:
Expression<Func<byte[]>> x = () => "hello"u8; // () => new [] {104, 101, 108, 108, 111}
Çözümleme:
Linq İfade Ağaçlarında Yasaklama - https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-01-26.md#expression-tree-representation.
(Çözüldü) u8 soneki olan bir dize'nin doğal tipi
"Ayrıntılı tasarım" bölümünde şu ifade yer alır: "Doğal tür ise ReadOnlySpan<byte>olacaktır." Buna ek olarak: "u8 soneki kullanıldığında, sabit hala izin verilen türlerden herhangi birine dönüştürülebilir: byte[], Span<byte> veya ReadOnlySpan<byte>."
Bu yaklaşımın çeşitli dezavantajları vardır:
-
ReadOnlySpan<byte>masaüstü çerçevesinde kullanılamaz; -
ReadOnlySpan<byte>'danbyte[]'e veyaSpan<byte>'ye mevcut dönüşüm yok. Bunları desteklemek için büyük olasılıkla değişmez değerleri hedef türü olarak ele almalıyız. Hem dil kuralları hem de uygulama daha karmaşık hale gelecektir.
Teklifi:
Doğal tür byte[]olacaktır. Tüm çerçevelerde kullanılabilir. Bu arada, özgün teklifle bile çalışma zamanında her zaman bir bayt dizisi oluşturmaya başlayacağız. ayrıca Span<byte> ve ReadOnlySpan<byte>dönüştürmelerini desteklemek için herhangi bir özel dönüştürme kuralına da ihtiyacımız yoktur.
byte[]'den Span<byte> ve ReadOnlySpan<byte>'a zaten örtük kullanıcı tanımlı dönüştürmeler vardır.
ReadOnlyMemory<byte>'a örtük bir kullanıcı tanımlı dönüştürme bile vardır (aşağıdaki "Dönüştürmenin derinliği" sorusuna bakın). Bir dezavantaj vardır, dil kullanıcı tanımlı dönüştürmeleri zincirleme izin vermez. Bu nedenle, aşağıdaki kod derlenmez:
using System;
class C
{
static void Main()
{
var y = (C2)"dog"u8; // error CS0030: Cannot convert type 'byte[]' to 'C2'
var z = (C3)"cat"u8; // error CS0030: Cannot convert type 'byte[]' to 'C3'
}
}
class C2
{
public static implicit operator C2(Span<byte> x) => new C2();
}
class C3
{
public static explicit operator C3(ReadOnlySpan<byte> x) => new C3();
}
Ancak, kullanıcı tanımlı dönüştürmelerde olduğu gibi, bir kullanıcı tanımlı dönüştürmeyi başka bir kullanıcı tanımlı dönüştürmenin parçası yapmak için açık bir atama kullanılabilir.
Tüm motive edici senaryoların doğal tür olarak byte[] ile ele alınacak gibi hissediliyor, ancak dil kuralları ve uygulama önemli ölçüde daha basit olacak.
Çözümleme:
Teklif onaylandı - https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-01-26.md#natural-type-of-u8-literals.
Muhtemelen u8 string literal'larının değiştirilebilir bir dizi türüne sahip olup olmadığını daha derinlemesine tartışmak isteyeceğiz, ancak şimdilik bu tartışmanın gerekli olduğunu düşünmüyoruz.
Yalnızca açık dönüştürme işleci uygulandı.
(Çözüldü) Dönüşümün derinliği
Byte[] ile çalışabilecek herhangi bir yerde de çalışır mı? Düşün:
static readonly ReadOnlyMemory<byte> s_data1 = "Data"u8;
static readonly ReadOnlyMemory<byte> s_data2 = "Data";
İlk örnek muhtemelen u8'dan gelen doğal özelliği nedeniyle çalışmalıdır.
İki yönde de dönüştürme gerektirdiğinden ikinci örneği yapmak zordur. Ancak ReadOnlyMemory<byte>'ı izin verilen dönüştürme türlerinden biri olarak eklemezsek durum bu olur.
Teklifi:
Özel bir şey yapma.
Çözümleme:
Şimdilik yeni dönüştürme hedefi eklenmedi https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-01-26.md#conversion-depth. Hiçbir dönüşüm derlenemiyor.
(Çözüldü) Aşırı yükleme çözümlemesi bozuldu
Aşağıdaki API belirsiz hale gelebilir:
M("");
static void M1(ReadOnlySpan<char> charArray) => ...;
static void M1(byte[] byteArray) => ...;
Bu sorunu çözmek için ne yapmalıyız?
Teklifi:
https://github.com/dotnet/csharplang/blob/main/proposals/csharp-10.0/lambda-improvements.md#overload-resolutionbenzer şekilde, Daha iyi işlev üyesi (§11.6.4.3), söz konusu dönüştürmelerin hiçbirinin string sabitlerinin UTF8 byte sıralarına dönüştürülmesini gerektirmediği üyeleri tercih etmek için güncelleştirilir.
Daha iyi işlev üyesi
... Bağımsız değişken listesi
, bir dizi bağımsız değişken ifadesi ve parametre türleri ve olan iki geçerli işlev üyesi ve ile birlikte verildiğinde, 'nın 'den daha iyi bir olduğu tanımlanır.işlev üyesi
- Her bağımsız değişken açısından,
Ex'denPx'ye olan örtük dönüşüm bir string_constant_to_UTF8_byte_representation_conversiondeğildir ve en az bir bağımsız değişken içinEx'tenQx'ya örtük dönüşüm bir string_constant_to_UTF8_byte_representation_conversionveya.- her bağımsız değişken için,
Ex'danPx'e örtük dönüştürme bir function_type_conversiondeğildir ve
Mpgenel olmayan bir yöntemdir veyaMp, tür parametreleri{X1, X2, ..., Xp}olan ve her tür parametresiXiiçin tür bağımsız değişkeninin bir ifadeden veya function_typedışındaki bir türden türetildiği genel bir yöntemdir ve- en az bir bağımsız değişken için,
Ex'denQx'ye örtük dönüşüm bir function_type_conversion'dur, veyaMq, tür parametreleri{Y1, Y2, ..., Yq}ile genel bir yöntem olma durumu taşıyan ve en az bir tür parametresiYiiçin tür bağımsız değişkeninin function_type'ten türetildiği bir durumdur, veya- her bağımsız değişken için,
Ex'denQx'ye örtük dönüştürme,Ex'denPx'a örtük dönüştürmeden daha iyi değildir ve en az bir bağımsız değişken içinEx'denPxdönüştürme,Ex'denQx'e dönüştürmeden daha iyidir.
Bu kuralın eklenmesi, örnek yöntemlerinin uygulanabilir hale gelmesi ve uzantı yöntemlerinin "gölgelenmesi" senaryolarını kapsamaz. Mesela:
using System;
class Program
{
static void Main()
{
var p = new Program();
Console.WriteLine(p.M(""));
}
public string M(byte[] b) => "byte[]";
}
static class E
{
public static string M(this object o, string s) => "string";
}
Bu kodun davranışı fark edilmeden "karakter dizisi" yazdırmaktan "byte[]" yazdıracak şekilde değişir.
Bu davranış değişikliğinde sorun yok mu? Önemli bir değişiklik olarak belgelenmeli mi?
C#10 dil sürümü hedeflendiğinde string_constant_to_UTF8_byte_representation_conversion'in kullanılamaz olması için bir teklif yapılmadığını unutmayın. Bu durumda, yukarıdaki örnek C#10 davranışına dönmek yerine hataya dönüşür. Bu, hedef dil sürümünün dilin semantiğini etkilemediği genel bir ilkeyi izler.
Bu davranış bizim için sorun değil mi? Önemli bir değişiklik olarak belgelenmeli mi?
Yeni kural, demet literal dönüşümlerini kapsayan kesintileri de engellemeyecek. Mesela
class C
{
static void Main()
{
System.Console.Write(Test(("s", 1)));
}
static string Test((object, int) a) => "object";
static string Test((byte[], int) a) => "array";
}
"'object' yerine sessizce 'array' yazdıracak."
Bu davranış bizim için sorun değil mi? Önemli bir değişiklik olarak belgelenmeli mi? Belki de demet literal dönüştürmelerini incelemek için yeni kuralı karmaşık hale getirebiliriz.
Çözümleme:
Prototip burada herhangi bir kuralda değişiklik yapmaz, bu nedenle uygulamada ne gibi sorunlar yaşayabileceğimizi görebiliriz - https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-01-26.md#breaking-changes.
(Çözüldü) u8 soneki büyük/küçük harfe duyarlı olmamalı mı?
Teklifi:
U8 son ekini sayısal soneklerle tutarlılık için destekleyin.
Çözümleme:
Onaylandı - https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-01-26.md#suffix-case-sensitivity.
Bugünkü örnekler
Çalışma zamanının UTF8 baytlarını bugün el ile kodladığı örnekler
- https://github.com/dotnet/runtime/blob/e095fde94baa480a6d65dfdee43d9cc0ad0d0b38/src/libraries/Common/src/System/Net/Http/aspnetcore/Http2/Hpack/StatusCodes.cs#L13-L78
- https://github.com/dotnet/runtime/blob/e095fde94baa480a6d65dfdee43d9cc0ad0d0b38/src/libraries/System.Memory/src/System/Buffers/Text/Base64Encoder.cs#L581-L591
- https://github.com/dotnet/runtime/blob/e095fde94baa480a6d65dfdee43d9cc0ad0d0b38/src/libraries/System.Net.HttpListener/src/System/Net/Windows/HttpResponseStream.Windows.cs#L284
- https://github.com/dotnet/runtime/blob/e095fde94baa480a6d65dfdee43d9cc0ad0d0b38/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http2Stream.cs#L30
- https://github.com/dotnet/runtime/blob/e095fde94baa480a6d65dfdee43d9cc0ad0d0b38/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http3RequestStream.cs#L852
- https://github.com/dotnet/runtime/blob/e095fde94baa480a6d65dfdee43d9cc0ad0d0b38/src/libraries/System.Text.Json/src/System/Text/Json/JsonConstants.cs#L35-L42
Perf'i tabloda bıraktığımız örnekler
- https://github.com/dotnet/runtime/blob/e095fde94baa480a6d65dfdee43d9cc0ad0d0b38/src/libraries/System.Net.Security/src/System/Net/Security/Pal.Managed/SafeChannelBindingHandle.cs#L16-L17
- https://github.com/dotnet/runtime/blob/e095fde94baa480a6d65dfdee43d9cc0ad0d0b38/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnection.cs#L37-L43
- https://github.com/dotnet/runtime/blob/e095fde94baa480a6d65dfdee43d9cc0ad0d0b38/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http2Connection.cs#L78
- https://github.com/dotnet/runtime/blob/e095fde94baa480a6d65dfdee43d9cc0ad0d0b38/src/libraries/System.Net.Mail/src/System/Net/Mail/SmtpCommands.cs#L669-L687
Tasarım toplantıları
https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-01-26.md https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-04-18.md https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-06-06.md
C# feature specifications