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.
.NET, yerelleştirilmiş ve genelleştirilmiş uygulamalar geliştirmek için kapsamlı destek sağlar ve dizeleri sıralama ve görüntüleme gibi yaygın işlemleri gerçekleştirirken geçerli kültürün veya belirli bir kültürün kurallarını uygulamayı kolaylaştırır. Ancak dizeleri sıralamak veya karşılaştırmak her zaman kültüre duyarlı bir işlem değildir. Örneğin, bir uygulama tarafından dahili olarak kullanılan dizeler genellikle tüm kültürlerde aynı şekilde işlenmelidir. XML etiketleri, HTML etiketleri, kullanıcı adları, dosya yolları ve sistem nesnelerinin adları gibi kültürel açıdan bağımsız dize verileri kültüre duyarlıymış gibi yorumlandığında, uygulama kodu ince hatalara, düşük performansa ve bazı durumlarda güvenlik sorunlarına tabi olabilir.
Bu makalede .NET'teki dize sıralama, karşılaştırma ve büyük/küçük harfe çevirme yöntemleri incelenerek, uygun bir dize işleme yöntemi seçmeye yönelik öneriler sunulur ve dize işleme yöntemleri hakkında ek bilgiler sağlanır.
Dize kullanımı için öneriler
.NET ile geliştirme yaparken, dizeleri karşılaştırırken bu önerileri izleyin.
Tavsiye
Dizeyle ilgili çeşitli yöntemler karşılaştırma gerçekleştirir. Örnek olarak String.Equals, String.Compare, String.IndexOfve String.StartsWithverilebilir.
- Dize işlemleri için dize karşılaştırma kurallarını açıkça belirten aşırı yüklemeleri kullanın. Bu durum genellikle, StringComparison türünde bir parametresi olan bir yöntem aşırı yüklemesini çağırmayı içerir.
- Kültürden bağımsız dize eşleştirme için güvenli varsayılan olarak StringComparison.Ordinal veya StringComparison.OrdinalIgnoreCase kullanın.
- StringComparison.Ordinal veya StringComparison.OrdinalIgnoreCase ile karşılaştırmaları kullanarak daha iyi performans elde edin.
- Kullanıcıya çıkış görüntülenirken StringComparison.CurrentCulture tabanlı dize işlemlerini kullanın.
- Karşılaştırmanın dilsel olarak ilgisiz (örneğin sembolik) olduğuna bağlı StringComparison.Ordinal olarak dize işlemleri yerine dilsel olmayan StringComparison.OrdinalIgnoreCase veya CultureInfo.InvariantCulture değerleri kullanın.
- Dizeleri karşılaştırma için normalleştirirken String.ToUpperInvariant yöntemini, String.ToLowerInvariant yöntemi yerine kullanın.
- İki dizenin eşit olup olmadığını test etmek için String.Equals yönteminin overload'ını kullanın.
- Dizeleri sıralamak için String.Compare ve String.CompareTo yöntemlerini, eşitliği denetlemek için değil, kullanın.
- Sayı ve tarih gibi dize olmayan verileri bir kullanıcı arabiriminde görüntülemek için kültüre duyarlı biçimlendirmeyi kullanın. Dize olmayan verileri dize biçiminde kalıcı hale getirmek için sabit kültürle biçimlendirmeyi kullanın.
Dizeleri karşılaştırırken kaçınmanız gereken aşağıdaki uygulamalardan:
- Dize işlemleri için dize karşılaştırma kurallarını açıkça veya örtük olarak belirtmeyen aşırı yüklemeler kullanmayın.
- Çoğu durumda tabanlı StringComparison.InvariantCulture dize işlemlerini kullanmayın. Birkaç özel durumdan biri, dilsel olarak anlamlı ancak kültürel olarak belirsiz verileri kalıcı hale getirmenizdir.
- Aşırı yüklenmiş String.Compare veya CompareTo yöntemlerini kullanmayın ve iki dizenin eşit olup olmadığını belirlemek için sıfır dönüş değerini test edin.
Tavsiye
CA1307, CA1309 ve CA1310 kod analizi kuralları, dil karşılaştırıcısının istemeden kullanıldığı çağrı sitelerini belirlemeye yardımcı olur. Bunları etkinleştirmek ve ihlalleri derleme hataları olarak ortaya çıkarabilmek için proje dosyanızda aşağıdaki özellikleri ayarlayın:
<PropertyGroup>
<AnalysisMode>All</AnalysisMode>
<WarningsAsErrors>$(WarningsAsErrors);CA1307;CA1309;CA1310</WarningsAsErrors>
</PropertyGroup>
Dize karşılaştırmalarını açıkça belirtin
.NET'teki dize işleme yöntemlerinin çoğu aşırı yüklenmiştir. Genellikle, bir veya daha fazla aşırı yükleme varsayılan ayarları kabul ederken, diğerleri varsayılanları kabul etmemektedir ve bunun yerine dizelerin karşılaştırılacağı veya değiştirileceği kesin yöntemi tanımlar. Varsayılanlara dayanmayan yöntemlerin çoğu, dize karşılaştırmasını kültüre ve büyük/küçük harfe göre açıkça belirten bir numaralandırma türünde StringComparison parametresi içerir. Aşağıdaki tabloda numaralandırma üyeleri açıklanmaktadır StringComparison .
StringComparison üye |
Açıklama |
|---|---|
| CurrentCulture | Geçerli kültürü kullanarak büyük/küçük harfe duyarlı bir karşılaştırma gerçekleştirir. |
| CurrentCultureIgnoreCase | Geçerli kültürü kullanarak büyük/küçük harfe duyarlı olmayan bir karşılaştırma gerçekleştirir. |
| InvariantCulture | Sabit kültürü kullanarak büyük/küçük harfe duyarlı bir karşılaştırma gerçekleştirir. |
| InvariantCultureIgnoreCase | Sabit kültürü kullanarak büyük/küçük harfe duyarsız bir karşılaştırma gerçekleştirir. |
| Ordinal | Sıralı bir karşılaştırma gerçekleştirir. |
| OrdinalIgnoreCase | Büyük/küçük harfe duyarsız sayısal karşılaştırma gerçekleştirir. |
Örneğin, IndexOf bir karakter veya dizeyle eşleşen bir nesnedeki bir String alt dizenin dizinini döndüren yönteminin dokuz aşırı yüklemesi vardır:
- IndexOf(Char), IndexOf(Char, Int32)ve IndexOf(Char, Int32, Int32), varsayılan olarak dizedeki bir karakter için sıralı (büyük/küçük harfe duyarlı ve kültüre duyarsız) arama yapar.
- IndexOf(String), IndexOf(String, Int32)ve IndexOf(String, Int32, Int32), dizedeki bir alt dize için varsayılan olarak büyük/küçük harfe duyarlı ve kültüre duyarlı bir arama gerçekleştirir.
- IndexOf(String, StringComparison), IndexOf(String, Int32, StringComparison)ve IndexOf(String, Int32, Int32, StringComparison), karşılaştırma biçiminin belirtilmesine izin veren türde StringComparison bir parametre içerir.
Aşağıdaki nedenlerle varsayılan değerleri kullanmayan bir aşırı yükleme seçmenizi öneririz:
Varsayılan parametreleri olan bazı aşırı yüklemeler (dize örneğinde Char arayanlar) ordinal bir karşılaştırma gerçekleştirirken, diğerleri (dize örneğinde bir dizeyi arayanlar) kültüre duyarlıdır. Hangi yöntemin hangi varsayılan değeri kullandığını hatırlamak zordur ve aşırı yüklemeleri karıştırmak kolaydır.
Yöntem çağrıları için varsayılan değerleri kullanan kodun amacı net değil. Varsayılan değerlere dayalı aşağıdaki örnekte, geliştiricinin aslında iki dizenin sıralı mı yoksa dilsel mi karşılaştırmasını amaçladığını veya
url.Schemeile "https" arasında büyük/küçük harf farkının eşitlik testindefalsedöndürmesine neden olup olmayacağını bilmek zordur.Uri url = new("https://learn.microsoft.com/"); // Incorrect if (string.Equals(url.Scheme, "https")) { // ...Code to handle HTTPS protocol. }Dim url As New Uri("https://learn.microsoft.com/") ' Incorrect If String.Equals(url.Scheme, "https") Then ' ...Code to handle HTTPS protocol. End If
Genel olarak, kodun amacını belirsiz hale getirdiğinden varsayılanlara güvenmeyen bir yöntemi çağırmanızı öneririz. Bu da kodun daha okunabilir olmasını ve hata ayıklamasını ve bakımının daha kolay olmasını sağlar. Aşağıdaki örnekte, önceki örnekle ilgili olarak sorulan sorular ele alınıyor. Sıralama karşılaştırmasının kullanıldığını ve büyük/küçük harf farklarının göz ardı edildiğini açıkça gösterir.
Uri url = new("https://learn.microsoft.com/");
// Correct
if (string.Equals(url.Scheme, "https", StringComparison.OrdinalIgnoreCase))
{
// ...Code to handle HTTPS protocol.
}
Dim url As New Uri("https://learn.microsoft.com/")
' Incorrect
If String.Equals(url.Scheme, "https", StringComparison.OrdinalIgnoreCase) Then
' ...Code to handle HTTPS protocol.
End If
Dize karşılaştırmasının ayrıntıları
Dize karşılaştırması, özellikle eşitlik için sıralama ve test etme olmak üzere dizeyle ilgili birçok işlemin kalbidir. Dizeler belirli bir düzende sıralanır: Eğer "my" kelimesi sıralanmış bir metin listesinde "string" kelimesinden önce geliyorsa, "my" değeri "string" ile eşit veya daha küçük olarak karşılaştırılmalıdır. Buna ek olarak, karşılaştırma örtük olarak eşitliği tanımlar. Karşılaştırma işlemi, eşit gördüğü dizeler için sıfır döndürür. İyi bir yorum, hiçbir dizenin diğerinden küçük olmamasıdır. Dizelerle ilgili en anlamlı işlemler şu yordamlardan birini veya her ikisini de içerir: başka bir dizeyle karşılaştırma ve iyi tanımlanmış bir sıralama işlemi yürütme.
Uyarı
Sıralama Ağırlığı Tablolarını, Windows işletim sistemleri için sıralama ve karşılaştırma işlemlerinde kullanılan karakter ağırlıkları hakkında bilgi içeren metin dosyaları kümesini ve Linux ve macOS için sıralama ağırlığı tablosunun en son sürümü olan Varsayılan Unicode Harmanlama Öğesi Tablosu'nu indirebilirsiniz. Linux ve macOS'ta sıralama ağırlığı tablosunun belirli sürümü, sistemde yüklü Unicode kitaplıkları için Uluslararası Bileşenler sürümüne bağlıdır. ICU sürümleri ve uyguladıkları Unicode sürümleri hakkında bilgi için bkz. ICU İndirme.
Ancak, iki dizeyi eşitlik veya sıralama düzeni için değerlendirmek tek ve doğru bir sonuç vermez; sonuç, dizeleri karşılaştırmak için kullanılan ölçütlere bağlıdır. Özellikle, ordinal olan veya geçerli kültürün ya da İngilizce dilini temel alan yerel ayardan bağımsız bir kültür olan sabit kültürün büyük/küçük harf farkı ve sıralama kurallarını temel alan dize karşılaştırmaları farklı sonuçlar verebilir.
Ayrıca, .NET'in farklı sürümlerini kullanan veya farklı işletim sistemlerinde veya işletim sistemi sürümlerinde .NET kullanan dize karşılaştırmaları farklı sonuçlar döndürebilir. .NET, desteklenen tüm platformlarda dil dizesi karşılaştırmaları için Unicode için Uluslararası Bileşenler (ICU) kitaplığını kullanır. Daha fazla bilgi için bkz. Dizeler, Unicode Standart ve .NET genelleştirmesi ve ICU.
Geçerli kültürü kullanan dize karşılaştırmaları
Bir ölçüt, dizeleri karşılaştırırken geçerli kültürün kurallarının kullanılmasını içerir. Geçerli kültürü temel alan karşılaştırmalar, iş parçacığının geçerli kültürünü veya yerel ayarını kullanır. Kültür kullanıcı tarafından ayarlanmadıysa, varsayılan olarak işletim sisteminin ayarına ayarlanır. Veriler dilsel olarak ilgili olduğunda ve kültüre duyarlı kullanıcı etkileşimini yansıttığında her zaman geçerli kültürü temel alan karşılaştırmalar kullanmalısınız.
Ancak bir kültür değiştiğinde .NET'teki karşılaştırma ve harf büyüklüğü davranışı değişir. Uygulama, uygulamanın geliştirildiği bilgisayardan farklı bir kültüre sahip bir bilgisayarda yürütürse veya yürütülen iş parçacığı kendi kültürünü değiştirdiğinde bu durum ortaya çıkar. Bu davranış kasıtlıdır, ancak birçok geliştirici için belirgin değildir. Aşağıdaki örnekte, ABD İngilizcesi ("en-US") ile İsveççe ("sv-SE") kültürleri arasındaki sıralama düzeni farklılıkları gösterilmektedir. "ångström", "Windows" ve "Visual Studio" sözcüklerinin sıralanmış dize dizilerinde farklı konumlarda göründüğüne dikkat edin.
using System.Globalization;
// Words to sort
string[] values= { "able", "ångström", "apple", "Æble",
"Windows", "Visual Studio" };
// Current culture
Array.Sort(values);
DisplayArray(values);
// Change culture to Swedish (Sweden)
string originalCulture = CultureInfo.CurrentCulture.Name;
Thread.CurrentThread.CurrentCulture = new CultureInfo("sv-SE");
Array.Sort(values);
DisplayArray(values);
// Restore the original culture
Thread.CurrentThread.CurrentCulture = new CultureInfo(originalCulture);
static void DisplayArray(string[] values)
{
Console.WriteLine($"Sorting using the {CultureInfo.CurrentCulture.Name} culture:");
foreach (string value in values)
Console.WriteLine($" {value}");
Console.WriteLine();
}
// The example displays the following output:
// Sorting using the en-US culture:
// able
// Æble
// ångström
// apple
// Visual Studio
// Windows
//
// Sorting using the sv-SE culture:
// able
// apple
// Visual Studio
// Windows
// ångström
// Æble
Imports System.Globalization
Imports System.Threading
Module Program
Sub Main()
' Words to sort
Dim values As String() = {"able", "ångström", "apple", "Æble",
"Windows", "Visual Studio"}
' Current culture
Array.Sort(values)
DisplayArray(values)
' Change culture to Swedish (Sweden)
Dim originalCulture As String = CultureInfo.CurrentCulture.Name
Thread.CurrentThread.CurrentCulture = New CultureInfo("sv-SE")
Array.Sort(values)
DisplayArray(values)
' Restore the original culture
Thread.CurrentThread.CurrentCulture = New CultureInfo(originalCulture)
End Sub
Sub DisplayArray(values As String())
Console.WriteLine($"Sorting using the {CultureInfo.CurrentCulture.Name} culture:")
For Each value As String In values
Console.WriteLine($" {value}")
Next
Console.WriteLine()
End Sub
End Module
' The example displays the following output:
' Sorting using the en-US culture:
' able
' Æble
' ångström
' apple
' Visual Studio
' Windows
'
' Sorting using the sv-SE culture:
' able
' apple
' Visual Studio
' Windows
' ångström
' Æble
Geçerli kültürü kullanan büyük/küçük harfe duyarsız karşılaştırmalar, iş parçacığının geçerli kültürü tarafından dikte edilen büyük/küçük harf kullanımını yoksaymaları dışında kültüre duyarlı karşılaştırmalarla aynıdır. Bu davranış, sıralama düzenlerinde de kendini gösterebilir.
Geçerli kültür semantiğini kullanan karşılaştırmalar aşağıdaki yöntemler için varsayılandır:
- String.Compare parametresi içermeyen StringComparison aşırı yüklemeler.
- String.CompareTo Aşırı yükler.
- Varsayılan String.StartsWith(String) yöntemi ve String.StartsWith(String, Boolean, CultureInfo) yöntemi,
nullCultureInfo parametresi ile birlikte. - Varsayılan String.EndsWith(String) yöntemi ve String.EndsWith(String, Boolean, CultureInfo) yöntemi,
nullCultureInfo parametresi ile birlikte. - String.IndexOf aşırı yükleri, arama parametresi olarak String kabul eden ve StringComparison parametresi olmayan.
- String.LastIndexOf aşırı yükleri, arama parametresi olarak String kabul eden ve StringComparison parametresi olmayan.
Her durumda, yöntem çağrısının amacını net hale getirmek için bir StringComparison parametresine sahip bir aşırı yüklemeyi çağırmanızı öneririz.
Dilsel olmayan dize verileri dilsel olarak yorumlandığında veya belirli bir kültüre ait dize verileri başka bir kültürün gelenekleri kullanılarak yorumlandığında ince ve bu kadar ince olmayan hatalar ortaya çıkar. En iyi bilinen örnek Turkish-I sorunudur.
ABD İngilizcesi de dahil olmak üzere neredeyse tüm Latin alfabelerinde "i" (\u0069) karakteri, "I" karakterinin küçük harfli sürümüdür (\u0049). Bu büyük/küçük harf kuralı, böyle bir kültürde programlayan biri için hızlı bir şekilde varsayılan hale gelir. Ancak, Türkçe ("tr-TR") alfabesinde "I with a dot" karakteri "İ" (\u0130) bulunur ve bu da "i" harfinin büyük versiyonudur. Türkçede, "ı" harfi, "I" olarak büyük harfe dönüşen noktasız küçük "i" karakterini de içerir (\u0131). Bu davranış Azerbaycan ("az") kültüründe de meydana gelir.
Bu nedenle, "i" harfini büyük harfe çevirme veya "I" harfini küçük harfe çevirme hakkında yapılan varsayımlar tüm kültürler arasında geçerli değildir. Dize karşılaştırma yordamları için varsayılan aşırı yüklemeleri kullanırsanız, bunlar kültürler arasında varyansa tabi olur. Karşılaştırılacak veriler dilsel değilse, yani dil ile ilgili değilse, "bill" ve "BILL" dizelerinin büyük/küçük harf duyarsız karşılaştırmasını gerçekleştirmeye çalışırken varsayılan aşırı yüklemelerin kullanılması, istenmeyen sonuçlara yol açabilir.
using System.Globalization;
string name = "Bill";
Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US");
Console.WriteLine($"Culture = {Thread.CurrentThread.CurrentCulture.DisplayName}");
Console.WriteLine($" Is 'Bill' the same as 'BILL'? {name.Equals("BILL", StringComparison.OrdinalIgnoreCase)}");
Console.WriteLine($" Does 'Bill' start with 'BILL'? {name.StartsWith("BILL", true, null)}");
Console.WriteLine();
Thread.CurrentThread.CurrentCulture = new CultureInfo("tr-TR");
Console.WriteLine($"Culture = {Thread.CurrentThread.CurrentCulture.DisplayName}");
Console.WriteLine($" Is 'Bill' the same as 'BILL'? {name.Equals("BILL", StringComparison.OrdinalIgnoreCase)}");
Console.WriteLine($" Does 'Bill' start with 'BILL'? {name.StartsWith("BILL", true, null)}");
//' The example displays the following output:
//'
//' Culture = English (United States)
//' Is 'Bill' the same as 'BILL'? True
//' Does 'Bill' start with 'BILL'? True
//'
//' Culture = Turkish (Türkiye)
//' Is 'Bill' the same as 'BILL'? True
//' Does 'Bill' start with 'BILL'? False
Imports System.Globalization
Imports System.Threading
Module Program
Sub Main()
Dim name As String = "Bill"
Thread.CurrentThread.CurrentCulture = New CultureInfo("en-US")
Console.WriteLine($"Culture = {Thread.CurrentThread.CurrentCulture.DisplayName}")
Console.WriteLine($" Is 'Bill' the same as 'BILL'? {name.Equals("BILL", StringComparison.OrdinalIgnoreCase)}")
Console.WriteLine($" Does 'Bill' start with 'BILL'? {name.StartsWith("BILL", True, Nothing)}")
Console.WriteLine()
Thread.CurrentThread.CurrentCulture = New CultureInfo("tr-TR")
Console.WriteLine($"Culture = {Thread.CurrentThread.CurrentCulture.DisplayName}")
Console.WriteLine($" Is 'Bill' the same as 'BILL'? {name.Equals("BILL", StringComparison.OrdinalIgnoreCase)}")
Console.WriteLine($" Does 'Bill' start with 'BILL'? {name.StartsWith("BILL", True, Nothing)}")
End Sub
End Module
' The example displays the following output:
'
' Culture = English (United States)
' Is 'Bill' the same as 'BILL'? True
' Does 'Bill' start with 'BILL'? True
'
' Culture = Turkish (Türkiye)
' Is 'Bill' the same as 'BILL'? True
' Does 'Bill' start with 'BILL'? False
Bu karşılaştırma, kültür aşağıdaki örnekte olduğu gibi güvenlik açısından hassas ayarlarda yanlışlıkla kullanılıyorsa önemli sorunlara neden olabilir. gibi IsFileURI("file:") bir yöntem çağrısı, geçerli kültürün ABD İngilizcesi olup olmadığını, ancak true geçerli kültürün Türkçe olup olmadığını döndürürfalse. Böylece, Türk sistemlerinde birisi "FILE:" ile başlayan büyük/küçük harfe duyarlı olmayan URI'lere erişimi engelleyen güvenlik önlemlerini atlatabilir.
public static bool IsFileURI(string path) =>
path.StartsWith("FILE:", true, null);
Public Shared Function IsFileURI(path As String) As Boolean
Return path.StartsWith("FILE:", True, Nothing)
End Function
Bu durumda, "dosya:" dilsel olmayan, kültüre duyarsız bir tanımlayıcı olarak yorumlanması amaçlandığından, kod bunun yerine aşağıdaki örnekte gösterildiği gibi yazılmalıdır:
public static bool IsFileURI(string path) =>
path.StartsWith("FILE:", StringComparison.OrdinalIgnoreCase);
Public Shared Function IsFileURI(path As String) As Boolean
Return path.StartsWith("FILE:", StringComparison.OrdinalIgnoreCase)
End Function
Sıralı dize işlemleri
Bir yöntem çağrısında StringComparison.Ordinal veya StringComparison.OrdinalIgnoreCase değerinin belirtilmesi, doğal dillerin özelliklerinin göz ardı edildiği dilsel olmayan bir karşılaştırmayı ifade eder. Bu StringComparison değerlerle çağrılan yöntemler, dize işlemi kararlarını kültüre göre parametreleştirilmiş büyük/küçük harf veya denklik tabloları yerine basit bayt karşılaştırmalarına dayandırır. Çoğu durumda bu yaklaşım, kodu daha hızlı ve daha güvenilir hale getirirken dizelerin hedeflenen yorumuna en uygun olanıdır.
Sıralı karşılaştırmalar, her dizenin her baytının dilsel yorum olmadan karşılaştırıldığı dize karşılaştırmalarıdır; örneğin, "windows" "Windows" ile eşleşmiyor. Bu temelde C çalışma zamanı strcmp işlevine yapılan bir çağrıdır. Bağlam dizelerin tam olarak eşleşmesini gerektiriyorsa veya muhafazakar eşleştirme ilkesi gerektiriyorsa bu karşılaştırmayı kullanın. Buna ek olarak, sıralı karşılaştırma en hızlı karşılaştırma işlemidir çünkü bir sonuç belirlerken dil kuralları uygulamaz.
Karşılaştırıcı OrdinalIgnoreCase hala karakter karakter temelinde çalışır, ancak işlemi gerçekleştirirken büyük/küçük harf farklarını ortadan kaldırır. Bir OrdinalIgnoreCase karşılaştırıcı altında, 'd' ve 'D' karakter çiftleri ile ve 'á' karakter çiftleri 'Á' olarak karşılaştırılır. Ancak vurgusuz karakter 'a', vurgulu karakter ile 'á' olarak değerlendirilir.
Bunun bazı örnekleri aşağıdaki tabloda verilmiştir:
| Dize 1 | Dize 2 |
Ordinal Karşılaştırma |
OrdinalIgnoreCase Karşılaştırma |
|---|---|---|---|
"dog" |
"dog" |
eşit | eşit |
"dog" |
"Dog" |
eşit değil | eşit |
"resume" |
"résumé" |
eşit değil | eşit değil |
Unicode ayrıca dizelerin birkaç farklı bellek içi gösterimine sahip olmasını sağlar. Örneğin, keskin e (é) iki olası şekilde temsil edilebilir.
- Tek bir değişmez
'é'karakteri (aynı zamanda'\u00E9'olarak da yazılır). - Vurgu içermeyen düz bir
'e'karakteri ve ardından birleşim vurgu değiştirici karakter'\u0301'.
Bu, aşağıdaki dört dizenin tümünün, kendi kurucu parçaları farklı olsa bile olarak "résumé"görüntülendiği anlamına gelir. Dizeler, harfi harfine 'é' karakterlerini veya harfi harfine aksansız 'e' karakterlerini artı kombine vurgu değiştiricisini '\u0301' kullanır.
"r\u00E9sum\u00E9""r\u00E9sume\u0301""re\u0301sum\u00E9""re\u0301sume\u0301"
Sıralı bir karşılaştırma kullanıldığında, bu dizelerden hiçbiri birbirine eşit olarak değerlendirilmez. Bunun nedeni, hepsi farklı temel karakter dizileri içermeleridir, ancak bunlar ekranda işlendiğinde hepsi aynı görünür.
Bir string.IndexOf(..., StringComparison.Ordinal) işlem gerçekleştirilirken çalışma zamanı tam bir alt dize eşleşmesi arar. Sonuçlar aşağıdaki gibidir.
Console.WriteLine("resume".IndexOf('e', StringComparison.Ordinal)); // "resume": prints '1'
Console.WriteLine("r\u00E9sum\u00E9".IndexOf('e', StringComparison.Ordinal)); // "résumé": prints '-1'
Console.WriteLine("r\u00E9sume\u0301".IndexOf('e', StringComparison.Ordinal)); // "résumé": prints '5'
Console.WriteLine("re\u0301sum\u00E9".IndexOf('e', StringComparison.Ordinal)); // "résumé": prints '1'
Console.WriteLine("re\u0301sume\u0301".IndexOf('e', StringComparison.Ordinal)); // "résumé": prints '1'
Console.WriteLine("resume".IndexOf('e', StringComparison.OrdinalIgnoreCase)); // "resume": prints '1'
Console.WriteLine("r\u00E9sum\u00E9".IndexOf('e', StringComparison.OrdinalIgnoreCase)); // "résumé": prints '-1'
Console.WriteLine("r\u00E9sume\u0301".IndexOf('e', StringComparison.OrdinalIgnoreCase)); // "résumé": prints '5'
Console.WriteLine("re\u0301sum\u00E9".IndexOf('e', StringComparison.OrdinalIgnoreCase)); // "résumé": prints '1'
Console.WriteLine("re\u0301sume\u0301".IndexOf('e', StringComparison.OrdinalIgnoreCase)); // "résumé": prints '1'
Sub IndexOfExample()
Console.WriteLine("resume".IndexOf("e"c, StringComparison.Ordinal)) ' "resume": prints '1'
Console.WriteLine(("r" & ChrW(&HE9) & "sum" & ChrW(&HE9)).IndexOf("e"c, StringComparison.Ordinal)) ' "résumé": prints '-1'
Console.WriteLine(("r" & ChrW(&HE9) & "sume" & ChrW(&H301)).IndexOf("e"c, StringComparison.Ordinal)) ' "résumé": prints '5'
Console.WriteLine(("re" & ChrW(&H301) & "sum" & ChrW(&HE9)).IndexOf("e"c, StringComparison.Ordinal)) ' "résumé": prints '1'
Console.WriteLine(("re" & ChrW(&H301) & "sume" & ChrW(&H301)).IndexOf("e"c, StringComparison.Ordinal)) ' "résumé": prints '1'
Console.WriteLine("resume".IndexOf("e"c, StringComparison.OrdinalIgnoreCase)) ' "resume": prints '1'
Console.WriteLine(("r" & ChrW(&HE9) & "sum" & ChrW(&HE9)).IndexOf("e"c, StringComparison.OrdinalIgnoreCase)) ' "résumé": prints '-1'
Console.WriteLine(("r" & ChrW(&HE9) & "sume" & ChrW(&H301)).IndexOf("e"c, StringComparison.OrdinalIgnoreCase)) ' "résumé": prints '5'
Console.WriteLine(("re" & ChrW(&H301) & "sum" & ChrW(&HE9)).IndexOf("e"c, StringComparison.OrdinalIgnoreCase)) ' "résumé": prints '1'
Console.WriteLine(("re" & ChrW(&H301) & "sume" & ChrW(&H301)).IndexOf("e"c, StringComparison.OrdinalIgnoreCase)) ' "résumé": prints '1'
End Sub
Sıralı arama ve karşılaştırma yordamları, geçerli iş parçacığının kültür ayarından hiçbir zaman etkilenmez.
.NET'teki dizeler eklenmiş null karakterler (ve diğer yazdırılmayan karakterler) içerebilir. Sıra ve kültüre duyarlı karşılaştırma (sabit kültürü kullanan karşılaştırmalar dahil) arasındaki en net farklardan biri, bir dizedeki katıştırılmış null karakterlerin işlenmesiyle ilgilidir. Kültüre duyarlı karşılaştırmalar (değişmez kültürü kullanan karşılaştırmalar dahil) gerçekleştirmek için String.Compare ve String.Equals yöntemlerini kullandığınızda bu karakterler yoksayılır. Sonuç olarak, eklenmiş null karakterler içeren dizeler, içermeyen dizelere eşit olarak kabul edilebilir. Yazdırılmayan ekli karakterler gibi String.StartsWithdize karşılaştırma yöntemleri için atlanabilir.
Önemli
Dize karşılaştırma yöntemleri eklenmiş null karakterleri dikkate almasa da, , String.Contains, String.EndsWithve String.IndexOfString.LastIndexOfgibi String.StartsWithdize arama yöntemleri bunu yapmaz.
Aşağıdaki örnek, "A" ile "a" arasında birkaç katıştırılmış null karakter içeren benzer bir dize ile "Aa" dizesinin kültüre duyarlı bir karşılaştırmasını gerçekleştirir ve iki dizenin nasıl eşit kabul edildiğini gösterir:
string str1 = "Aa";
string str2 = "A" + new string('\u0000', 3) + "a";
Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.GetCultureInfo("en-us");
Console.WriteLine($"Comparing '{str1}' ({ShowBytes(str1)}) and '{str2}' ({ShowBytes(str2)}):");
Console.WriteLine(" With String.Compare:");
Console.WriteLine($" Current Culture: {string.Compare(str1, str2, StringComparison.CurrentCulture)}");
Console.WriteLine($" Invariant Culture: {string.Compare(str1, str2, StringComparison.InvariantCulture)}");
Console.WriteLine(" With String.Equals:");
Console.WriteLine($" Current Culture: {string.Equals(str1, str2, StringComparison.CurrentCulture)}");
Console.WriteLine($" Invariant Culture: {string.Equals(str1, str2, StringComparison.InvariantCulture)}");
string ShowBytes(string value)
{
string hexString = string.Empty;
for (int index = 0; index < value.Length; index++)
{
string result = Convert.ToInt32(value[index]).ToString("X4");
result = string.Concat(" ", result.Substring(0,2), " ", result.Substring(2, 2));
hexString += result;
}
return hexString.Trim();
}
// The example displays the following output:
// Comparing 'Aa' (00 41 00 61) and 'Aa' (00 41 00 00 00 00 00 00 00 61):
// With String.Compare:
// Current Culture: 0
// Invariant Culture: 0
// With String.Equals:
// Current Culture: True
// Invariant Culture: True
Module Program
Sub Main()
Dim str1 As String = "Aa"
Dim str2 As String = "A" & New String(Convert.ToChar(0), 3) & "a"
Console.WriteLine($"Comparing '{str1}' ({ShowBytes(str1)}) and '{str2}' ({ShowBytes(str2)}):")
Console.WriteLine(" With String.Compare:")
Console.WriteLine($" Current Culture: {String.Compare(str1, str2, StringComparison.CurrentCulture)}")
Console.WriteLine($" Invariant Culture: {String.Compare(str1, str2, StringComparison.InvariantCulture)}")
Console.WriteLine(" With String.Equals:")
Console.WriteLine($" Current Culture: {String.Equals(str1, str2, StringComparison.CurrentCulture)}")
Console.WriteLine($" Invariant Culture: {String.Equals(str1, str2, StringComparison.InvariantCulture)}")
End Sub
Function ShowBytes(str As String) As String
Dim hexString As String = String.Empty
For ctr As Integer = 0 To str.Length - 1
Dim result As String = Convert.ToInt32(str.Chars(ctr)).ToString("X4")
result = String.Concat(" ", result.Substring(0, 2), " ", result.Substring(2, 2))
hexString &= result
Next
Return hexString.Trim()
End Function
' The example displays the following output:
' Comparing 'Aa' (00 41 00 61) and 'Aa' (00 41 00 00 00 00 00 00 00 61):
' With String.Compare:
' Current Culture: 0
' Invariant Culture: 0
' With String.Equals:
' Current Culture: True
' Invariant Culture: True
End Module
Ancak, aşağıdaki örnekte gösterildiği gibi sıralı karşılaştırma kullandığınızda dizeler eşit kabul edilmez:
string str1 = "Aa";
string str2 = "A" + new String('\u0000', 3) + "a";
Console.WriteLine($"Comparing '{str1}' ({ShowBytes(str1)}) and '{str2}' ({ShowBytes(str2)}):");
Console.WriteLine(" With String.Compare:");
Console.WriteLine($" Ordinal: {string.Compare(str1, str2, StringComparison.Ordinal)}");
Console.WriteLine(" With String.Equals:");
Console.WriteLine($" Ordinal: {string.Equals(str1, str2, StringComparison.Ordinal)}");
string ShowBytes(string str)
{
string hexString = string.Empty;
for (int ctr = 0; ctr < str.Length; ctr++)
{
string result = Convert.ToInt32(str[ctr]).ToString("X4");
result = " " + result.Substring(0, 2) + " " + result.Substring(2, 2);
hexString += result;
}
return hexString.Trim();
}
// The example displays the following output:
// Comparing 'Aa' (00 41 00 61) and 'A a' (00 41 00 00 00 00 00 00 00 61):
// With String.Compare:
// Ordinal: 97
// With String.Equals:
// Ordinal: False
Module Program
Sub Main()
Dim str1 As String = "Aa"
Dim str2 As String = "A" & New String(Convert.ToChar(0), 3) & "a"
Console.WriteLine($"Comparing '{str1}' ({ShowBytes(str1)}) and '{str2}' ({ShowBytes(str2)}):")
Console.WriteLine(" With String.Compare:")
Console.WriteLine($" Ordinal: {String.Compare(str1, str2, StringComparison.Ordinal)}")
Console.WriteLine(" With String.Equals:")
Console.WriteLine($" Ordinal: {String.Equals(str1, str2, StringComparison.Ordinal)}")
End Sub
Function ShowBytes(str As String) As String
Dim hexString As String = String.Empty
For ctr As Integer = 0 To str.Length - 1
Dim result As String = Convert.ToInt32(str.Chars(ctr)).ToString("X4")
result = String.Concat(" ", result.Substring(0, 2), " ", result.Substring(2, 2))
hexString &= result
Next
Return hexString.Trim()
End Function
' The example displays the following output:
' Comparing 'Aa' (00 41 00 61) and 'A a' (00 41 00 00 00 00 00 00 00 61):
' With String.Compare:
' Ordinal: 97
' With String.Equals:
' Ordinal: False
End Module
Büyük/küçük harfe duyarsız sıralı karşılaştırmalar bir sonraki en muhafazakar yaklaşımdır. Bu karşılaştırmalar, çoğu büyük/küçük harf farkını görmezden gelir; örneğin, "windows" "Windows" ile eşleşir. ASCII karakterleriyle ilgilenirken, bu ilke ile eşdeğerdir StringComparison.Ordinal, ancak normal ASCII büyük/küçük harflerini yoksayar. Bu nedenle, [A, Z] (\u0041-\u005A) içindeki tüm karakterler [a,z] (\u0061-\007A) içindeki ilgili karakterle eşleşir. ASCII aralığının dışındaki harf büyüklüğü, değişmez kültürün tablolarını kullanır. Bu nedenle, aşağıdaki karşılaştırma:
string.Compare(strA, strB, StringComparison.OrdinalIgnoreCase);
String.Compare(strA, strB, StringComparison.OrdinalIgnoreCase)
bu karşılaştırmaya eşdeğerdir (ancak daha hızlıdır):
string.Compare(strA.ToUpperInvariant(), strB.ToUpperInvariant(), StringComparison.Ordinal);
String.Compare(strA.ToUpperInvariant(), strB.ToUpperInvariant(), StringComparison.Ordinal)
Bu karşılaştırmalar hala çok hızlıdır.
Hem StringComparison.Ordinal hem de StringComparison.OrdinalIgnoreCase ikili değerleri doğrudan kullanır ve eşleştirme için en uygun olanlarıdır. Karşılaştırma ayarlarınızdan emin değilseniz bu iki değerden birini kullanın. Ancak, bayt bayt karşılaştırması yaptıkları için, dilsel sıralama düzenine (İngilizce sözlük gibi) göre değil, ikili sıralama düzenine göre sıralarlar. Kullanıcılara görüntülenirse çoğu bağlamda sonuçlar garip görünebilir.
Ordinal semantik, String.Equals bağımsız değişkeni içermeyen StringComparison aşırı yüklemeler (eşitlik işleci dahil) için varsayılandır. Her durumda, parametresi olan StringComparison bir aşırı yüklemeyi çağırmanızı öneririz.
Dilsel dize karşılaştırmaları
Dilsel arama ve karşılaştırma yordamları bir dizeyi harmanlama öğelerine ayırır ve bu öğeler üzerinde aramalar veya karşılaştırmalar yapar. Bir dizenin karakterleriyle bileşen harmanlama öğeleri arasında 1:1 eşlemesi olması şart değildir. Örneğin, uzunluğu 2 olan bir dize yalnızca tek bir harmanlama öğesinden oluşabilir. İki dize dil bilincine sahip bir şekilde karşılaştırıldığında, karşılaştırıcı, dizenin harfleri farklı olsa bile iki dizenin harmanlama öğelerinin aynı anlama sahip olup olmadığını denetler.
Dizeyi "résumé" ve önceki bölümde açıklanan dört farklı gösterimini göz önünde bulundurun. Aşağıdaki tabloda her gösterimi harmanlama öğelerine ayrılmış olarak gösterilmektedir.
| String | Harmanlama öğeleri olarak |
|---|---|
"r\u00E9sum\u00E9" |
"r" + "\u00E9" + "s" + "u" + "m" + "\u00E9" |
"r\u00E9sume\u0301" |
"r" + "\u00E9" + "s" + "u" + "m" + "e\u0301" |
"re\u0301sum\u00E9" |
"r" + "e\u0301" + "s" + "u" + "m" + "\u00E9" |
"re\u0301sume\u0301" |
"r" + "e\u0301" + "s" + "u" + "m" + "e\u0301" |
Harmanlama öğesi, okuyucuların tek bir karakter veya karakter kümesi olarak düşüneceği şeylere gevşek bir şekilde karşılık gelir. Kavramsal olarak grafeme kümesine benzer ancak biraz daha büyük bir şemsiyeyi kapsar.
Dil karşılaştırması altında tam eşleşmeler gerekli değildir. Harmanlama öğeleri bunun yerine anlamsal anlamlarına göre karşılaştırılır. Örneğin, dil karşılaştırıcısı alt dizeleri "\u00E9" eşit "e\u0301" olarak ele alır çünkü her ikisi de anlamsal olarak "akut aksan değiştiricisi olan küçük harfli e" anlamına gelir. Bu, yönteminin IndexOf"e\u0301" aşağıdaki kod örneğinde gösterildiği gibi, eşanlamlı olarak eşdeğer alt dizeyi "\u00E9"içeren daha büyük bir dize içindeki alt dizeyle eşleşmesini sağlar.
Console.WriteLine("r\u00E9sum\u00E9".IndexOf("e")); // "résumé": prints '-1' (not found)
Console.WriteLine("r\u00E9sum\u00E9".IndexOf("\u00E9")); // "résumé": prints '1'
Console.WriteLine("\u00E9".IndexOf("e\u0301")); // prints '0'
Sub IndexOfStringExample()
Console.WriteLine(("r" & ChrW(&HE9) & "sum" & ChrW(&HE9)).IndexOf("e")) ' "résumé": prints '-1' (not found)
Console.WriteLine(("r" & ChrW(&HE9) & "sum" & ChrW(&HE9)).IndexOf(ChrW(&HE9).ToString())) ' "résumé": prints '1'
Console.WriteLine(ChrW(&HE9).ToString().IndexOf("e" & ChrW(&H301))) ' prints '0'
End Sub
Bunun bir sonucu olarak, dil karşılaştırması kullanılıyorsa farklı uzunluklarda iki dize eşit olarak karşılaştırılabilir. Çağıranların, bu tür senaryolarda dize uzunluğuyla ilgilenen özel durum mantığına dikkat etmemesi gerekir.
Kültüre duyarlı arama ve karşılaştırma yordamları, dilsel arama ve karşılaştırma yordamlarının özel bir biçimidir. Kültüre duyarlı bir karşılaştırıcı altında harmanlama öğesi kavramı, belirtilen kültüre özgü bilgileri içerecek şekilde genişletilir.
Örneğin, Macar alfabesinde iki dz< karakteri >arka arkaya göründüğünde, d< veya >z'den <>ayrı kendi benzersiz harfleri olarak kabul edilirler. Bu, bir dizede <dz> görüldüğünde, Macar kültüre duyarlı bir karşılaştırıcının bunu tek bir harmanlama öğesi olarak değerlendirdiği anlamına gelir.
| String | Harmanlama öğeleri olarak | Açıklamalar |
|---|---|---|
"endz" |
"e" + "n" + "d" + "z" |
(standart dil karşılaştırıcı kullanarak) |
"endz" |
"e" + "n" + "dz" |
(Macar kültürüne duyarlı bir karşılaştırıcı kullanarak) |
Macar kültürüne duyarlı bir karşılaştırıcı kullanılırken, dize "endz" alt dize ile "z", çünkü <dz> ve <z> farklı anlamsal anlamlara sahip harmanlama öğeleri olarak kabul edilir.
// Set thread culture to Hungarian
CultureInfo.CurrentCulture = CultureInfo.GetCultureInfo("hu-HU");
Console.WriteLine("endz".EndsWith("z")); // Prints 'False'
// Set thread culture to invariant culture
CultureInfo.CurrentCulture = CultureInfo.InvariantCulture;
Console.WriteLine("endz".EndsWith("z")); // Prints 'True'
' Set thread culture to Hungarian
CultureInfo.CurrentCulture = CultureInfo.GetCultureInfo("hu-HU")
Console.WriteLine("endz".EndsWith("z")) ' Prints 'False'
' Set thread culture to invariant culture
CultureInfo.CurrentCulture = CultureInfo.InvariantCulture
Console.WriteLine("endz".EndsWith("z")) ' Prints 'True'
Uyarı
- Davranış: Dilbilimsel ve kültüre duyarlı karşılaştırıcılar zaman zaman davranışsal ayarlamalar yapabilir. Hem ICU hem de eski Windows NLS tesisi, dünya dillerinin nasıl değiştiğini dikkate almak için güncelleştirilir. Daha fazla bilgi için yerel ayar (kültür) veri değişim sıklığı blog gönderisine bakın. Tam bit düzeyinde arama ve karşılaştırma gerçekleştirdiğinden Sıra karşılaştırıcısının davranışı hiçbir zaman değişmez. Bununla birlikte, Unicode daha fazla karakter kümesini kapsayacak şekilde büyüdükçe ve mevcut harf yazımı verilerindeki eksiklikleri düzelttikçe OrdinalIgnoreCase karşılaştırıcısının davranışı değişebilir.
-
Kullanım: Karşılaştırıcılar
StringComparison.InvariantCultureveStringComparison.InvariantCultureIgnoreCasekültüre duyarlı olmayan dil karşılaştırıcılarıdır. Yani, bu karşılaştırıcılar vurgulanmış karakter é'nin birden çok olası temel gösterime sahip olması gibi kavramları anlar ve bu tür tüm gösterimlerin eşit olarak ele alınması gerekir. Ancak kültüre duyarlı olmayan dil karşılaştırıcıları, yukarıda gösterildiği gibi, <dz>'yi <d> veya <z>'den farklı olarak özel bir işleme tabi tutmaz. Ayrıca Almanca Eszett (ß) gibi harfler için özel bir durum tanımazlar.
.NET ayrıca sabit genelleştirme modunu da sunar. Bu kabul etme modu, dilsel arama ve karşılaştırma yordamlarıyla ilgilenen kod yollarını devre dışı bırakır. Bu modda, çağıranın sağladığı
Sabit kültürü kullanan dize işlemleri
Sabit kültürle yapılan karşılaştırmalar, statik CompareInfo özelliği tarafından döndürülen CultureInfo.InvariantCulture özelliğini kullanır. Bu davranış tüm sistemlerde aynıdır; aralığının dışındaki karakterleri eşdeğer sabit karakterler olduğuna inandığı değere çevirir. Bu ilke, kültürler arasında bir metin dizisi davranışını korumak için yararlı olabilir, ancak sıklıkla beklenmedik sonuçlar verir.
Değişmez kültürle yapılan büyük/küçük harfe duyarsız karşılaştırmalar için karşılaştırma bilgilerini almak amacıyla CompareInfo ve CultureInfo.InvariantCulture statik özellikleri de kullanılır. Bu çevrilen karakterler arasındaki tüm büyük/küçük harf farkları yoksayılır.
ASCII dizeleri üzerinde StringComparison.InvariantCulture ve StringComparison.Ordinal kullanan karşılaştırmalar aynı şekilde çalışır. Ancak, StringComparison.InvariantCulture bayt kümesi olarak yorumlanması gereken dizeler için uygun olmayan dilsel kararlar verir.
CultureInfo.InvariantCulture.CompareInfo nesnesi, Compare yönteminin belirli karakter kümelerini eşdeğer olarak yorumlamasını sağlar. Örneğin, sabit kültür altında aşağıdaki denklik geçerlidir:
InvariantCulture: a + ̊ = å
LATIN KÜÇÜK HARF A karakteri "a" (\u0061), "+ " ̊" (\u030a) ÜST HALKA İŞARETİ karakterinin yanında olduğunda, ÜST HALKA İŞARETLİ LATIN KÜÇÜK HARF A karakteri "å" (\u00e5) olarak yorumlanır. Aşağıdaki örnekte gösterildiği gibi, bu davranış sıralı karşılaştırmadan farklıdır.
string separated = "\u0061\u030a";
string combined = "\u00e5";
Console.WriteLine($"Equal sort weight of {separated} and {combined} using InvariantCulture: {string.Compare(separated, combined, StringComparison.InvariantCulture) == 0}");
Console.WriteLine($"Equal sort weight of {separated} and {combined} using Ordinal: {string.Compare(separated, combined, StringComparison.Ordinal) == 0}");
// The example displays the following output:
// Equal sort weight of a° and å using InvariantCulture: True
// Equal sort weight of a° and å using Ordinal: False
Module Program
Sub Main()
Dim separated As String = ChrW(&H61) & ChrW(&H30A)
Dim combined As String = ChrW(&HE5)
Console.WriteLine("Equal sort weight of {0} and {1} using InvariantCulture: {2}",
separated, combined,
String.Compare(separated, combined, StringComparison.InvariantCulture) = 0)
Console.WriteLine("Equal sort weight of {0} and {1} using Ordinal: {2}",
separated, combined,
String.Compare(separated, combined, StringComparison.Ordinal) = 0)
' The example displays the following output:
' Equal sort weight of a° and å using InvariantCulture: True
' Equal sort weight of a° and å using Ordinal: False
End Sub
End Module
Dosya adlarını, tanımlama bilgilerini veya "å" gibi bir bileşimin görüntülenebildiği başka bir şeyi yorumlarken sıralı karşılaştırmalar yine de en saydam ve en uygun davranışı sunar.
Genel olarak, sabit kültürün karşılaştırma için yararlı kılan pek az özelliği vardır. Dil açısından ilgili şekilde karşılaştırma yapar, bu da tam sembolik denkliği garanti etmesini önler, ancak hiçbir kültürde sergileme tercihi değildir. Karşılaştırma için kullanmanın StringComparison.InvariantCulture birkaç nedenden biri, sıralı verileri kültürler arası özdeş bir görüntü için kalıcı hale getirmektir. Örneğin, görüntüleme için sıralanmış tanımlayıcıların bir listesini içeren büyük bir veri dosyası bir uygulamaya eşlik ettiğinde, bu listeye ekleme yapmak değişmez tarzda sıralama ile ekleme gerektirir.
StringComparison üyesini nasıl seçersiniz
Aşağıdaki tabloda, anlamsal dize bağlamından bir StringComparison numaralandırma üyesine eşleme özetlenmiştir:
| Veri | Davranış | İlgili System.StringComparison değer |
|---|---|---|
| Büyük/küçük harfe duyarlı iç tanımlayıcılar. XML ve HTTP gibi standartlarda büyük/küçük harfe duyarlı tanımlayıcılar. Büyük/küçük harfe duyarlı güvenlikle ilgili ayarlar. |
Baytların tam olarak eşleştiği dilsel olmayan bir tanımlayıcı. | Ordinal |
| Büyük/küçük harfe duyarlı olmayan iç tanımlayıcılar. XML ve HTTP gibi standartlarda harf büyüklüğüne duyarlı olmayan tanımlayıcılar. Dosya yolları. Kayıt defteri anahtarları ve değerleri. Ortam değişkenleri. Kaynak tanımlayıcıları (örneğin, tanıtıcı adları). Büyük/küçük harfe duyarlı olmayan güvenlikle ilgili ayarlar. |
Büyük/küçük harfle ilgisiz olan dilsel olmayan bir tanımlayıcı. | OrdinalIgnoreCase |
| Bazı kalıcı, dilsel olarak ilgili veriler. Sabit bir sıralama düzeni gerektiren dilsel verilerin görüntülenmesi. |
Kültürel açıdan herhangi bir tarafa eğilim göstermeyen, ancak dilsel açıdan ilgili veriler. | InvariantCulture -veya- InvariantCultureIgnoreCase |
| Kullanıcıya görüntülenen veriler. Çoğu kullanıcı girişi. |
Yerel dilsel gelenekler gerektiren veriler. | CurrentCulture -veya- CurrentCultureIgnoreCase |
Güvenlik etkileri
Uygulamanız filtreleme veya erişim denetimi için dize API'leri kullanıyorsa sıralı karşılaştırmaları kullanın. Geçerli kültüre dayalı dil karşılaştırmaları, platforma ve yerel ayara göre değişen beklenmeyen sonuçlara neden olabilir. Aşağıdaki gibi kod desenleri güvenlik açıklarına açık olabilir:
//
// THIS SAMPLE CODE IS INCORRECT.
// DO NOT USE IT IN PRODUCTION.
//
bool ContainsHtmlSensitiveCharacters(string input)
{
if (input.IndexOf("<") >= 0) { return true; }
if (input.IndexOf("&") >= 0) { return true; }
return false;
}
'
' THIS SAMPLE CODE IS INCORRECT.
' DO NOT USE IT IN PRODUCTION.
'
Function ContainsHtmlSensitiveCharacters(input As String) As Boolean
If input.IndexOf("<") >= 0 Then Return True
If input.IndexOf("&") >= 0 Then Return True
Return False
End Function
string.IndexOf(string) yöntemi varsayılan olarak dil araması kullandığından, bir dizenin değişmez '<' veya '&' karakter içermesi ve bunun sonucu olarak string.IndexOf(string)'ün -1 döndürülmesi, arama alt dizesinin bulunamadığını gösterir. Kod çözümleme kuralları CA1307 ve CA1309 bu tür arama sitelerini işaretler ve geliştiriciyi olası bir sorun olduğu konusunda uyarır.
.NET'te yaygın dize karşılaştırma yöntemleri
Aşağıdaki bölümlerde, dize karşılaştırması için en yaygın olarak kullanılan yöntemler açıklanmaktadır.
String.Compare
Varsayılan yorum: StringComparison.CurrentCulture.
Dize yorumlamanın en merkezi işlemi olan bu yöntem çağrılarının tüm örnekleri, dizelerin geçerli kültüre göre yorumlanıp yorumlanmayacağını veya kültürle (sembolik olarak) ilişkilendirilip ilişkilendirilmeyeceğini belirlemek için incelenmelidir. Genellikle bu ikinci seçenektir ve bunun yerine bir StringComparison.Ordinal karşılaştırma kullanılmalıdır.
System.Globalization.CompareInfo özelliği tarafından döndürülen CultureInfo.CompareInfo sınıfı, Compare bayrak enumerasyonu aracılığıyla çok sayıda eşleştirme seçeneği (sıralı, boşluk yoksayma, kana türünü yoksayma vb.) sağlayan bir CompareOptions yöntem de içerir.
String.CompareTo
Varsayılan yorum: StringComparison.CurrentCulture.
Bu yöntem şu anda bir StringComparison türünü belirten bir yükleme seçeneği sunmaz. Genellikle bu yöntemi önerilen String.Compare(String, String, StringComparison) forma dönüştürmek mümkündür.
IComparable ve IComparable<T> arabirimlerini uygulayan türler bu yöntemi uygular.
StringComparison parametresini sunmadığı için, tiplerin uygulanması genellikle kullanıcının oluşturucusunda bir StringComparer belirtmesine olanak tanır. Aşağıdaki örnek, sınıf kurucusunun bir FileName parametresini içeren bir StringComparer sınıfı tanımlar. Bu StringComparer nesne daha sonra FileName.CompareTo yönteminde kullanılır.
class FileName : IComparable
{
private readonly StringComparer _comparer;
public string Name { get; }
public FileName(string name, StringComparer? comparer)
{
if (string.IsNullOrEmpty(name)) throw new ArgumentNullException(nameof(name));
Name = name;
if (comparer != null)
_comparer = comparer;
else
_comparer = StringComparer.OrdinalIgnoreCase;
}
public int CompareTo(object? obj)
{
if (obj == null) return 1;
if (obj is not FileName)
return _comparer.Compare(Name, obj.ToString());
else
return _comparer.Compare(Name, ((FileName)obj).Name);
}
}
Class FileName
Implements IComparable
Private ReadOnly _comparer As StringComparer
Public ReadOnly Property Name As String
Public Sub New(name As String, comparer As StringComparer)
If (String.IsNullOrEmpty(name)) Then Throw New ArgumentNullException(NameOf(name))
Me.Name = name
If comparer IsNot Nothing Then
_comparer = comparer
Else
_comparer = StringComparer.OrdinalIgnoreCase
End If
End Sub
Public Function CompareTo(obj As Object) As Integer Implements IComparable.CompareTo
If obj Is Nothing Then Return 1
If TypeOf obj IsNot FileName Then
Return _comparer.Compare(Name, obj.ToString())
Else
Return _comparer.Compare(Name, DirectCast(obj, FileName).Name)
End If
End Function
End Class
String.Equals
Varsayılan yorum: StringComparison.Ordinal.
sınıfı, String statik veya örnek Equals yöntemi aşırı yüklemelerini çağırarak veya statik eşitlik işlecini kullanarak eşitliği test etmenizi sağlar. Aşırı yüklemeler ve işleç varsayılan olarak sıralı karşılaştırmayı kullanır. Ancak, ordinal bir karşılaştırma yapmak isteseniz bile türü açıkça belirten StringComparison bir aşırı yüklemeyi çağırmanızı öneririz; bu, belirli bir dize yorumlamasını kodda bulmanızı kolaylaştırır.
String.ToUpper ve String.ToLower
Varsayılan yorum: StringComparison.CurrentCulture.
String.ToUpper() ve String.ToLower() yöntemlerini kullanırken dikkatli olun, çünkü bir dizeyi büyük veya küçük harfe dönüştürmek genellikle dizeleri büyük/küçük harfe bakılmaksızın karşılaştırmak için ufak bir normalleştirme olarak kullanılır. Öyleyse, harf duyarsız bir karşılaştırma kullanmayı göz önünde bulundurun.
String.ToUpperInvariant ve String.ToLowerInvariant yöntemleri de kullanılabilir. ToUpperInvariant büyük/küçük harf normalleştirmenin standart yoludur. Karşılaştırmalar StringComparison.OrdinalIgnoreCase kullanılarak yapıldığında, davranışsal olarak iki çağrının bileşimidir: her iki dize bağımsız değişkeninde ToUpperInvariant çağırmak ve StringComparison.Ordinal kullanarak karşılaştırma yapmak.
Aşırı yüklemeler, yöntemine bu kültürü temsil eden bir CultureInfo nesne geçirilerek belirli bir kültürde büyük ve küçük harfe dönüştürülebilir.
Char.ToUpper ve Char.ToLower
Varsayılan yorum: StringComparison.CurrentCulture.
Char.ToUpper(Char) ve Char.ToLower(Char) yöntemleri, önceki bölümde açıklanan String.ToUpper() ve String.ToLower() yöntemlerine benzer şekilde çalışır.
String.StartsWith ve String.EndsWith
Varsayılan yorumlama: StringComparison.CurrentCulture (ilk parametre bir stringolduğunda ) veya StringComparison.Ordinal (ilk parametre bir charolduğunda).
Bu yöntemlerin varsayılan aşırı yüklemelerinin karşılaştırmaları gerçekleştirmesinde bir tutarsızlık vardır. Parametreyi char kabul eden aşırı yüklemeler sıralı bir karşılaştırma gerçekleştirir, ancak parametreyi string kabul eden aşırı yüklemeler kültüre duyarlı bir karşılaştırma gerçekleştirir ve yazdırılmayan karakterleri yoksayabilir.
String.IndexOf ve String.LastIndexOf
Varsayılan yorum: StringComparison.CurrentCulture.
Bu yöntemlerin varsayılan aşırı yüklemelerinin karşılaştırmaları gerçekleştirmesinde tutarlılık eksikliği vardır. Parametre içeren tüm String.IndexOf ve String.LastIndexOf yöntemler sıralı bir karşılaştırma gerçekleştirir, ancak varsayılan Char ve String.IndexOf parametre içeren String.LastIndexOf yöntemler kültüre duyarlı String bir karşılaştırma gerçekleştirir.
String.IndexOf(String) veya String.LastIndexOf(String) yöntemini çağırır ve geçerli örnekte bulmak için bir dize geçirirseniz, türü açıkça belirten bir StringComparison aşırı yüklemesini çağırmanızı öneririz. Char bağımsız değişkeni içeren aşırı yüklemeler, bir StringComparison türü belirtmenize izin vermez.
String.Contains
Varsayılan yorum: StringComparison.Ordinal.
String.IndexOf yönteminden farklı olarak, String.Contains yöntemi, hem char hem de string aşırı yüklemeler için varsayılan olarak sıralı bir karşılaştırma kullanır. Ancak, niyet önemli olduğunda, çağrı noktasında davranışı net hale getirmek için açık bir StringComparison bağımsız değişken geçirmeniz gerekir.
MemoryExtensions.AsSpan.IndexOfAny ve SearchValues<T> türü
.NET 8, spanler içindeki belirli karakter veya bayt kümelerini aramak için iyileştirilmiş bir çözüm sağlayan SearchValues<T> türünü tanıttı.
Bir dizeyi sabit bir bilinen değer kümesiyle sürekli karşılaştırıyorsanız zincirleme karşılaştırmalar veya LINQ tabanlı yaklaşımlar yerine yöntemini kullanmayı SearchValues<T>.Contains(T) göz önünde bulundurun.
SearchValues<T> iç arama yapılarını önceden derleyebilir ve sağlanan değerlere göre karşılaştırma mantığını iyileştirebilir. Performans avantajlarını görmek için örneği bir kez oluşturup önbelleğe alın SearchValues<string> , ardından karşılaştırmalar için yeniden kullanabilirsiniz:
using System.Buffers;
namespace ExampleCode;
internal partial class DemoCode
{
private static readonly SearchValues<string> Commands =
SearchValues.Create(
["start", "run", "go", "begin", "commence"],
StringComparison.OrdinalIgnoreCase);
void ProcessCommand(string command)
{
if (Commands.Contains(command))
{
// ...
}
}
}
Imports System.Buffers
Namespace ExampleCode
Partial Friend Class DemoCode
Private Shared ReadOnly Commands As SearchValues(Of String) =
SearchValues.Create(
{"start", "run", "go", "begin", "commence"},
StringComparison.OrdinalIgnoreCase)
Sub ProcessCommand(command As String)
If Commands.Contains(command) Then
' ...
End If
End Sub
End Class
End Namespace
.NET 9'da, SearchValues daha büyük bir dize içinde alt dize aramayı destekleyecek şekilde genişletilmiştir. Bir örnek için bkz SearchValues . genişletme.
Dolaylı olarak dize karşılaştırması gerçekleştiren yöntemler
Merkezi bir işlem olarak dize karşılaştırması olan bazı dize dışı yöntemler türünü kullanır StringComparer . StringComparer sınıfı, StringComparer örneklerini döndüren altı statik özellik içerir; bu örneklerin StringComparer.Compare yöntemleri, aşağıdaki dize karşılaştırması türlerini gerçekleştirir:
- Geçerli kültüre göre duyarlı dize karşılaştırmaları. Bu StringComparer nesne, StringComparer.CurrentCulture özelliğiyle döndürülür.
- Geçerli kültürü kullanarak harf büyüklüğüne duyarsız karşılaştırmalar. Bu StringComparer nesne, StringComparer.CurrentCultureIgnoreCase özelliğiyle döndürülür.
- Sabit kültürün sözcük karşılaştırma kuralları kullanılarak kültüre duyarsız karşılaştırmalar. Bu StringComparer nesne, StringComparer.InvariantCulture özelliğiyle döndürülür.
- Sabit kültürün sözcük karşılaştırma kuralları kullanılarak, kültüre ve büyük/küçük harfe duyarsız karşılaştırmalar yapılır. Bu StringComparer nesne, StringComparer.InvariantCultureIgnoreCase özelliğiyle döndürülür.
- Sıralı karşılaştırma. Bu StringComparer nesne, StringComparer.Ordinal özelliğiyle döndürülür.
- Büyük/küçük harfe duyarsız sıralı karşılaştırma. Bu StringComparer nesne, StringComparer.OrdinalIgnoreCase özelliğiyle döndürülür.
Array.Sort ve Array.BinarySearch
Varsayılan yorum: StringComparison.CurrentCulture.
Bir koleksiyonda herhangi bir veri depoladığınızda veya bir dosyadan veya veritabanından kalıcı verileri koleksiyona okuduğunuzda, geçerli kültürün değiştirilmesi koleksiyondaki sabitleri geçersiz kılabilir. yöntemi, Array.BinarySearch aranacak dizideki öğelerin zaten sıralandığını varsayar. Dizideki herhangi bir dize öğesini sıralamak için Array.Sort yöntemi, tek tek öğeleri sıralamak için String.Compare yöntemini çağırır. Kültüre duyarlı bir karşılaştırıcı kullanmak, dizinin sıralandığı ve içindekilerin aranacağı zaman arasında kültür değiştiğinde tehlikeli olabilir. Örneğin, aşağıdaki kodda depolama ve alma işlemi, Thread.CurrentThread.CurrentCulture özelliği tarafından dolaylı yoldan sağlanan karşılaştırıcı üzerinde çalışır. Kültür, StoreNames ve DoesNameExist çağrıları arasında değişebilir ve özellikle dizi içeriği iki yöntem çağrısı arasında bir yerde kalıcı hale getirilmişse, ikili arama başarısız olabilir.
// Incorrect
string[] _storedNames;
public void StoreNames(string[] names)
{
_storedNames = new string[names.Length];
// Copy the array contents into a new array
Array.Copy(names, _storedNames, names.Length);
Array.Sort(_storedNames); // Line A
}
public bool DoesNameExist(string name) =>
Array.BinarySearch(_storedNames, name) >= 0; // Line B
' Incorrect
Dim _storedNames As String()
Sub StoreNames(names As String())
ReDim _storedNames(names.Length - 1)
' Copy the array contents into a new array
Array.Copy(names, _storedNames, names.Length)
Array.Sort(_storedNames) ' Line A
End Sub
Function DoesNameExist(name As String) As Boolean
Return Array.BinarySearch(_storedNames, name) >= 0 ' Line B
End Function
Aşağıdaki örnekte, diziyi sıralamak ve aramak için aynı sıralı (kültüre duyarsız) karşılaştırma yöntemini kullanan önerilen bir varyasyon gösterilir. Değişiklik kodu, iki örnekte Line A ve Line B olarak etiketlenmiş satırlara yansıtılır.
// Correct
string[] _storedNames;
public void StoreNames(string[] names)
{
_storedNames = new string[names.Length];
// Copy the array contents into a new array
Array.Copy(names, _storedNames, names.Length);
Array.Sort(_storedNames, StringComparer.Ordinal); // Line A
}
public bool DoesNameExist(string name) =>
Array.BinarySearch(_storedNames, name, StringComparer.Ordinal) >= 0; // Line B
' Correct
Dim _storedNames As String()
Sub StoreNames(names As String())
ReDim _storedNames(names.Length - 1)
' Copy the array contents into a new array
Array.Copy(names, _storedNames, names.Length)
Array.Sort(_storedNames, StringComparer.Ordinal) ' Line A
End Sub
Function DoesNameExist(name As String) As Boolean
Return Array.BinarySearch(_storedNames, name, StringComparer.Ordinal) >= 0 ' Line B
End Function
Bu veriler kalıcı hale gelirse ve kültürler arasında taşınırsa ve bu verileri kullanıcıya sunmak için sıralama kullanılırsa, daha iyi kullanıcı çıktısı için dilsel olarak çalışan ancak kültürdeki değişikliklerden etkilenmeyen öğesini kullanmayı StringComparison.InvariantCulturedüşünebilirsiniz. Aşağıdaki örnek, diziyi sıralamak ve aramak için sabit kültürü kullanmak üzere önceki iki örneği değiştirir.
// Correct
string[] _storedNames;
public void StoreNames(string[] names)
{
_storedNames = new string[names.Length];
// Copy the array contents into a new array
Array.Copy(names, _storedNames, names.Length);
Array.Sort(_storedNames, StringComparer.InvariantCulture); // Line A
}
public bool DoesNameExist(string name) =>
Array.BinarySearch(_storedNames, name, StringComparer.InvariantCulture) >= 0; // Line B
' Correct
Dim _storedNames As String()
Sub StoreNames(names As String())
ReDim _storedNames(names.Length - 1)
' Copy the array contents into a new array
Array.Copy(names, _storedNames, names.Length)
Array.Sort(_storedNames, StringComparer.InvariantCulture) ' Line A
End Sub
Function DoesNameExist(name As String) As Boolean
Return Array.BinarySearch(_storedNames, name, StringComparer.InvariantCulture) >= 0 ' Line B
End Function
Koleksiyonlar örneği: Hashtable oluşturucu
Hashleme işlemi, dizelerin karşılaştırılma şeklinin etkilediği bir işlemin ikinci örneğini gösterir.
Aşağıdaki örnek, Hashtable özelliği tarafından döndürülen StringComparer nesnesini geçirerek bir StringComparer.OrdinalIgnoreCase nesnesinin örneğini oluşturur. Bir sınıf `StringComparer`'den türetildiği ve `StringComparer` arabirimini uyguladığı için, `c3` yöntemi, karma tablosundaki dizelerin hash kodunu hesaplamak için kullanılır.
using System.IO;
using System.Collections;
const int InitialCapacity = 100;
Hashtable creationTimeByFile = new(InitialCapacity, StringComparer.OrdinalIgnoreCase);
string directoryToProcess = Directory.GetCurrentDirectory();
// Fill the hash table
PopulateFileTable(directoryToProcess);
// Get some of the files and try to find them with upper cased names
foreach (var file in Directory.GetFiles(directoryToProcess))
PrintCreationTime(file.ToUpper());
void PopulateFileTable(string directory)
{
foreach (string file in Directory.GetFiles(directory))
creationTimeByFile.Add(file, File.GetCreationTime(file));
}
void PrintCreationTime(string targetFile)
{
object? dt = creationTimeByFile[targetFile];
if (dt is DateTime value)
Console.WriteLine($"File {targetFile} was created at time {value}.");
else
Console.WriteLine($"File {targetFile} does not exist.");
}
Imports System.IO
Module Program
Const InitialCapacity As Integer = 100
Private ReadOnly s_creationTimeByFile As New Hashtable(InitialCapacity, StringComparer.OrdinalIgnoreCase)
Private ReadOnly s_directoryToProcess As String = Directory.GetCurrentDirectory()
Sub Main()
' Fill the hash table
PopulateFileTable(s_directoryToProcess)
' Get some of the files and try to find them with upper cased names
For Each File As String In Directory.GetFiles(s_directoryToProcess)
PrintCreationTime(File.ToUpper())
Next
End Sub
Sub PopulateFileTable(directoryPath As String)
For Each file As String In Directory.GetFiles(directoryPath)
s_creationTimeByFile.Add(file, IO.File.GetCreationTime(file))
Next
End Sub
Sub PrintCreationTime(targetFile As String)
Dim dt As Object = s_creationTimeByFile(targetFile)
If TypeOf dt Is Date Then
Console.WriteLine($"File {targetFile} was created at time {DirectCast(dt, Date)}.")
Else
Console.WriteLine($"File {targetFile} does not exist.")
End If
End Sub
End Module
Koleksiyonlar örneği: SortedSet<T> ve List<T>.Sort
Aynı yerel ayar duyarlılığı sorunu, sıralanmış dize koleksiyonunun örneğini oluştururken veya var olan dize tabanlı bir koleksiyonu sıralarken de geçerlidir. Her zaman açık bir karşılaştırıcı belirtin:
// Words to sort
string[] values = [ "able", "ångström", "apple", "Æble",
"Windows", "Visual Studio" ];
//
// Potentially incorrect code - behavior might vary based on locale.
//
SortedSet<string> mySet = [.. values]; // No comparer specified
List<string> list = [.. values];
list.Sort(); // No comparer specified
//
// Corrected code - uses ordinal sorting; doesn't vary by locale.
//
SortedSet<string> mySet2 = new(values, StringComparer.Ordinal);
List<string> list2 = [.. values];
list2.Sort(StringComparer.Ordinal);
' Words to sort
Dim values As String() = {"able", "ångström", "apple", "Æble",
"Windows", "Visual Studio"}
'
' Potentially incorrect code - behavior might vary based on locale.
'
Dim mySet As New SortedSet(Of String)(values) ' No comparer specified
Dim list As New List(Of String)(values)
list.Sort() ' No comparer specified
'
' Corrected code - uses ordinal sorting; doesn't vary by locale.
'
Dim mySet2 As New SortedSet(Of String)(values, StringComparer.Ordinal)
Dim list2 As New List(Of String)(values)
list2.Sort(StringComparer.Ordinal)
.NET ile .NET Framework arasındaki farklar
.NET ve .NET Framework genelleştirmeyi farklı işler. Windows üzerinde .NET Framework, dil dizesi karşılaştırmaları için işletim sisteminin Ulusal Dil Desteği (NLS) tesisini kullanır. .NET, desteklenen tüm platformlarda dil dizesi karşılaştırmaları için Unicode için Uluslararası Bileşenler (ICU) kitaplığını kullanır.
ICU ve NLS dil karşılaştırıcılarında farklı mantık uyguladığından, kültüre duyarlı karşılaştırma kullanan dize yöntemlerinin sonuçları .NET ile .NET Framework arasında farklılık gösterebilir. Bu, aşağıdakiler dahil olmak üzere varsayılan olarak dil karşılaştırıcısı kullanan tüm yöntemler için önemlidir:
- String.Compare
-
String.EndsWith (ilk parametre bir
stringolduğunda ) -
String.IndexOf (ilk parametre bir
stringolduğunda ) -
String.StartsWith (ilk parametre bir
stringolduğunda ) - String.ToLower
- String.ToLowerInvariant
- String.ToUpper
- String.ToUpperInvariant
- System.Globalization.TextInfo (çoğu üye)
- System.Globalization.CompareInfo (çoğu üye)
- Array.Sort (dize dizilerini sıralarken)
- List<T>.Sort() (liste öğeleri dize olduğunda)
- System.Collections.Generic.SortedDictionary<TKey,TValue> (anahtarlar dize olduğunda)
- System.Collections.Generic.SortedList<TKey,TValue> (anahtarlar dize olduğunda)
- System.Collections.Generic.SortedSet<T> (küme dizeler içerdiğinde)
Uyarı
Bu, etkilenen API'lerin kapsamlı bir listesi değildir.
Önemli bir fark, katıştırılmış null ve diğer denetim karakterlerinin işlenmesidir. NLS altında dil karşılaştırması kullandığınızda, null karakter (\0) gibi bazı denetim karakterleri bazı karşılaştırma bağlamlarında göz ardı edilebilir. ICU altında, bu karakterler dizedeki gerçek karakterler olarak değerlendirilir. Bu, arama dizesi null karakter içerdiğinde farklı sonuçlar döndürmeye neden string.IndexOf(string) olabilir.
Örneğin, aşağıdaki kod geçerli çalışma zamanına bağlı olarak farklı bir yanıt üretebilir:
const string greeting = "Hel\0lo";
Console.WriteLine($"{greeting.IndexOf("\0")}");
// The snippet prints:
//
// '3' when running on .NET Framework and .NET Core 2.x - 3.x (Windows)
// '0' when running on .NET 5 or later (Windows)
// '0' when running on .NET Core 2.x - 3.x or .NET 5 (non-Windows)
// '3' when running on .NET Core 2.x or .NET 5+ (in invariant mode)
Const greeting As String = "Hel" & vbNullChar & "lo"
Console.WriteLine($"{greeting.IndexOf(CStr(vbNullChar))}")
' The snippet prints:
'
' '3' when running on .NET Framework and .NET Core 2.x - 3.x (Windows)
' '0' when running on .NET 5 or later (Windows)
' '0' when running on .NET Core 2.x - 3.x or .NET 5 (non-Windows)
' '3' when running on .NET Core 2.x or .NET 5+ (in invariant mode)
Bu platformlar arası ve uygulamalar arası sürprizlerden kaçınmanın en iyi yolu, dize karşılaştırma yöntemlerine her zaman açık StringComparison bir bağımsız değişken geçirmek ve dilsel olmayan karşılaştırmalar için StringComparison.Ordinal veya StringComparison.OrdinalIgnoreCase kullanmaktır.
Bir uygulamayı .NET Framework'ten .NET'e geçirir ve Windows'da eski NLS davranışlarına güvenirseniz, uygulamayı NLS kullanacak şekilde yapılandırabilirsiniz. Daha fazla bilgi için bkz. .NET genelleştirme ve ICU.