.NET'te dizeleri karşılaştırmak için en iyi yöntemler
.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 dizelerin genellikle tüm kültürlerde aynı şekilde işlenmeleri gerekir. XML etiketleri, HTML etiketleri, kullanıcı adları, dosya yolları ve sistem nesnelerinin adları gibi kültürden bağımsız dize verileri kültüre duyarlıymış gibi yorumlanırsa, uygulama kodu küçük hatalar, zayıf performans ve bazı durumlarda güvenlik sorunlarıyla karşılaşabilir.
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.
İpucu
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. Genellikle bu, StringComparison türünde bir parametreye sahip olan bir yöntem aşırı yüklemesini çağırmayı içerir.
- Güvenli varsayılan olarak kültürden bağımsız dize karşılaştırmalarınız için StringComparison.Ordinal veya StringComparison.OrdinalIgnoreCase kullanın.
- Daha iyi performans için StringComparison.Ordinal veya StringComparison.OrdinalIgnoreCase ile karşılaştırma kullanın.
- Kullanıcıya çıktı görüntülerken StringComparison.CurrentCulture öğesini temel alan dize işlemlerini kullanın.
- Karşılaştırma dilsel olarak alakasız iken (örneğin simgesel olduğunda), StringComparison.Ordinal öğesini temel alan dize işlemleri yerine dilsel olmayan StringComparison.OrdinalIgnoreCase veya CultureInfo.InvariantCulture değerlerini kullanın.
- Karşılaştırma için dizelerinizi normalleştirirken String.ToUpperInvariant yöntemi yerine String.ToLowerInvariant yöntemini kullanın.
- İki dizenin eşit olup olmadığını test etmek için String.Equals yönteminin bir aşırı yüklemesini kullanın.
- Eşit olup olmadıklarını kontrol etmek için değil, dizeleri sıralamak için String.Compare ve String.CompareTo yöntemlerini kullanın.
- Sayılar ve tarihler gibi dize olmayan verileri bir kullanıcı arabiriminde görüntülemek için kültüre duyarlı biçimlendirme 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 aşağıdaki uygulamalardan kaçının:
- 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.
- veya CompareTo yönteminin aşırı yüklemesini kullanmayın ve iki dizenin String.Compare eşit olup olmadığını belirlemek için sıfır dönüş değerini test edin.
Dize karşılaştırmalarını açıkça belirtme
.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 etmez ve bunun yerine dizelerin tam olarak nasıl karşılaştırılacağını veya değiştirileceğini tanımlar. Varsayılanlara dayanmayan yöntemlerin çoğu, kültür ve büyük/küçük harfe göre dize karşılaştırması kurallarını açıkça belirten bir numaralandırma olan türünde StringComparisonbir parametre içerir. Aşağıdaki tablo, StringComparison numaralandırma üyelerini açıklar.
StringComparison üyesi | 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 duyarsız 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 duyarlı olmayan sıralı bir karşılaştırma gerçekleştirir. |
Örneğin, bir karakteri veya bir dizeyi eşleştiren bir IndexOf nenesindeki alt dizine ait dizeyi döndüren String 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.
- Karşılaştırma biçiminin belirlenmesini sağlayan IndexOf(String, StringComparison) türü bir parametreyi içeren IndexOf(String, Int32, StringComparison), IndexOf(String, Int32, Int32, StringComparison) ve StringComparison.
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 bir Char arayanlar) sıralı bir karşılaştırma gerçekleştirirken diğerleri (dize örneğinde bir dize 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ı olan aşağıdaki örnekte, geliştiricinin aslında iki dizenin sıralı veya dilsel karşılaştırmasını mı amaçladığını ya da ile "https" arasındaki
url.Scheme
bir büyük/küçük harf farkının eşitlik testinin döndürmesinefalse
neden olup olmadığı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 sayede kod daha okunabilir olur ve hata ayıklaması ve bakımı daha kolay hale gelir. Aşağıdaki örnek, önceki örnekle ilgili oluşturulan soruları ele alır. Sıralı karşılaştırmanın kullanıldığını ve büyük/küçük harfteki farkların yok sayıldığını belirtir.
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ırma, özellikle sıralama ve eşitlik testi gibi, dizeyle ilgili pek çok işlemin temelidir. Dizeler belirli bir düzende sıralanır: Eğer dizelerin sıralı bir listesinde "my" dizesi "string" dizesinden önce görünüyorsa, "my" dizesi "string" dizesi ile karşılaştırıldığında daha küçük veya eşit olmalıdır. Ek olarak, karşılaştırma dolaylı olarak eşitliği tanımlar. Karşılaştırma işlemi, eşit olarak gördüğü dizeler için sıfır döndürür. İki dizenin de diğerinden daha az olmaması iyi bir yorumdur. Dizeleri içeren en anlamlı işlemler, şu yordamların birini veya her ikisini içerir: başka bir dize ile karşılaştırma ve iyi tanımlanmış bir sıralama işlemini yürütme.
Not
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, sıralı olan veya geçerli kültürün veya sabit kültürün (İngilizce dilini temel alan yerel ayardan bağımsız bir kültür ) büyük/küçük harf 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. Daha fazla bilgi için bkz . Dizeler ve Unicode Standardı.
Geçerli kültürü kullanan dize karşılaştırmaları
Ölçütlerden biri, dizeleri karşılaştırırken geçerli kültüre ait kuralları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 ayarlarını kullanır. Kültür kullanıcı tarafından ayarlanmadıysa, varsayılan olarak işletim sisteminin ayarına ayarlanır. Veriler dilsel 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 kültür değiştiğinde .NET'teki karşılaştırma ve büyük/küçük harf davranışı değişir. Bu, bir uygulama geliştirildiği bilgisayardakinden farklı bir kültüre sahip olan başka bir bilgisayarda yürütüldüğünde veya uygulamayı yürüten iş parçacığı kültürünü değiştirdiğinde gerçekleşir. Bu davranış kasıtlıdır, ancak çoğu geliştirici için belirgin değildir. Aşağıdaki örnek, sıralama düzeninin A.B.D. İngilizce ("en-US") ve İsveççe ("sv-SE") kültürleri arasındaki farkını gösterir. "å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 ve büyük/küçük harfe duyarlı olmayan karşılaştırmalar, kültüre duyarlı karşılaştırmalarla aynıdır, ancak iş parçacığının geçerli kültürü tarafından belirtilen büyük/küçük harfi göz ardı eder. Bu davranış kendisini sıralama düzenlerinde de gösterebilir.
Geçerli kültürün semantiklerini kullanan karşılaştırmalar aşağıdaki yöntemler için varsayılan değerdir:
- String.Compare parametresi içermeyen StringComparison aşırı yüklemeler.
- String.CompareTo aşırı yüklemeleri.
- Varsayılan String.StartsWith(String) yöntemi ve bir String.StartsWith(String, Boolean, CultureInfo)
null
parametresi olan CultureInfo yöntemi. - Varsayılan String.EndsWith(String) yöntemi ve bir String.EndsWith(String, Boolean, CultureInfo)
null
parametresi olan CultureInfo yöntemi. - String.IndexOf bir arama parametresi olarak kabul String eden ve parametresi olmayan StringComparison aşırı yükler.
- String.LastIndexOf bir arama parametresi olarak kabul String eden ve parametresi olmayan StringComparison aşırı yükler.
Her durumda, metodun çağrı amacını belli etmek için StringComparison parametresi olan bir aşırı yüklemeyi çağırmanızı öneririz.
Dilsel olmayan veriler dilsel olarak yorumlandığında veya belirli bir kültürdeki dize verileri başka bir kültürün kuralları kullanılarak yorumlandığında küçük ve küçük olmayan hatalar oluşabilir. Kurallı örnek, Türkçe-I sorunudur.
A.B.D. İngilizce dahil olmak üzere neredeyse tüm Latin alfabelerinde, "i" karakteri (\u0069) "I" karakterinin (\u0049) küçük harfli halidir. Bu büyük/küçük harf kuralı bunun gibi bir kültürde programlama yapan birisi için hızla varsayılan hale gelir. Ancak, Türkçe ("tr-TR") alfabesi, "i" karakterinin büyük harfli hali olan "Noktalı I" karakteri, yani "İ" (\u0130) içerir. Türkçe ayrıca büyük harfi "I" olan "noktasız i", yani "ı" (\u0131) karakterini içerir. Bu davranış Azerbaycan dili ("az") kültüründe de bulunur.
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. Eğer dize karşılaştırma yordamları için varsayılan aşırı yüklemeleri kullanırsanız, bunlar kültürler arasındaki farktan etkilenir. Karşılaştırılacak veriler dilsel değilse, aşağıdaki "bill" ve "BILL" dizelerinin büyük/küçük harfe duyarlı olmayan karşılaştırmasını gerçekleştirme girişimi gösterildiği gibi varsayılan aşırı yüklemelerin kullanılması istenmeyen sonuçlara neden olabilir.
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, eğer kültür güvenliğe duyarlı yerlerde farkında olunmadan kullanılıyorsa aşağıdaki örnekteki gibi önemli sorunlara neden olabilir. IsFileURI("file:")
gibi bir yöntem çağrısı, eğer geçerli kültür A.B.D. İngilizce ise true
'i döndürürken, geçerli kültür Türkçe ise false
'i döndürür. Bu nedenle, Türkçe sistemlerde "FILE:" ile başlayan büyük/küçük harfe duyarsız URI değerlerine olan erişimi engelleyen güvenlik önlemleri aşılabilir.
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ğerini belirtmek, doğal dillerin özelliklerinin göz ardı edildiği dilsel olmayan bir karşılaştırmayı belirtir. Bu StringComparison değerleriyle çağırılan yöntemler, temel dize işlemi kararlarında kültür tarafından parametre haline getirilen büyük/küçük harf veya eşitlik tabloları yerine basit bayt karşılaştırmalarını temel alır. Çoğu durumda, bu yaklaşım dizelerin istenen şekilde yorumlanmasının yanı sıra kodun daha hızlı ve daha güvenilir olmasını sağlar.
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 aslında C çalışma zamanı strcmp
işlevine yapılan bir çağrıdır. Bağlam, dizelerin tam olarak karşılaşmasını gerektirdiğinde veya koruyucu bir eşleştirme ilkesine sahip olduğunda bu karşılaştırmayı kullanın. Ek olarak, sıralı karşılaştırma, sonuç oluştururken dilsel kurallar uygulamadığından en hızlı karşılaştırma işlemidir.
.NET'teki dizeler eklenmiş null karakterler (ve diğer yazdırılmayan karakterler) içerebilir. Sıralı ve kültüre duyarlı karşılaştırmalar (sabit kültür kullanan karşılaştırmalar dahil) arasındaki en belirgin farklardan biri bir dizedeki gömülü null karakterlerin işlenmesiyle ilgilidir. Bu karakterler, kültüre duyarlı karşılaştırmalar (sabit kültür kullanan karşılaştırmalar dahil) yapmak için String.Compare ve String.Equals yöntemlerini kullandığınızda yok sayı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 gömülü null karakterleri yok saysa da, String.Contains, String.EndsWith, String.IndexOf, String.LastIndexOf ve String.StartsWith gibi dize arama yöntemleri bu karakterleri yok saymaz.
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 bundan sonraki en koruyucu yaklaşımdır. Bu karşılaştırmalar, çoğu büyük/küçük harfi yok sayar; örneğin, "windows" ile "Windows" eşleşir. ASCII karakterleri ile çalışırken bu ilke StringComparison.Ordinal ile eşdeğerdir, ancak tek farkı genel ASCII büyük/küçük harflerini yok saymasıdır. Bu nedenle, [A, Z] (\u0041-\u005A) içindeki herhangi bir karakter [a,z] (\u0061-\007A) içindeki karşılık gelen karakterle eşleşir. ASCII aralığı dışındaki büyük/küçük harf kuralları sabit 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 yine de çok hızlıdır.
StringComparison.Ordinal ve StringComparison.OrdinalIgnoreCase'in her ikisi de doğrudan ikili değerleri kullanır ve eşleştirme için idealdir. 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. Sonuçlar kullanıcılara görüntülenirse çoğu bağlamda tuhaf görünebilir.
Sıralı semantik, bağımsız değişken içermeyen StringComparison aşırı yüklemeler için String.Equals varsayılan değerdir (eşitlik işleci dahil). Her durumda StringComparison parametresi olan bir aşırı yüklemeyi çağırmanızı öneririz.
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ığı dışındaki karakterleri eşdeğer sabit karakter olarak düşündüğü karakterlere çevirir. Bu ilke, kültürler arası tek bir dize davranışı bulundurmak için kullanışlı olabilir, ancak genellikle beklenmeyen sonuçlar sağlar.
Sabit kültürle yapılan büyük/küçük harfe duyarsız karşılaştırmalar, karşılaştırma bilgisi için statik CompareInfo özelliğinden döndürülen statik CultureInfo.InvariantCulture özelliğini kullanır. Bu çevrilen karakterler arasındaki tüm büyük/küçük harf farkları yok sayılır.
StringComparison.InvariantCulture ve StringComparison.Ordinal kullanan karşılaştırmalar ASCII dizelerinde de aynı şekilde çalışır. Ancak StringComparison.InvariantCulture, bir bayt kümesi olarak yorumlanması gereken dizeler için uygun olmayabilecek dilsel kararlar alır. CultureInfo.InvariantCulture.CompareInfo
nesnesi Compare yönteminin belirli karakter kümelerini eşdeğer olarak yorumlamasını sağlar. Örneğin, aşağıdaki eşitlik sabit kültürde geçerlidir:
InvariantCulture: a + ̊ = ş
LATIN KÜÇÜK HARF A karakteri "a" (\u0061), "+ " ̊" (\u030a) BİRLEŞTİRİ HALKASI karakterinin yanında olduğunda, LATIN KÜÇÜK HARF A VE ÜSTÜNDE HALKA 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 {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
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.
Dengede, sabit kültürün karşılaştırma için yararlı hale getiren birkaç özelliği vardır. Dilsel olarak ilgili bir şekilde karşılaştırma yapar ve bu da tam sembolik denkliği garanti etmesini önler, ancak herhangi bir kültürde görüntüleme seçeneği değildir. Karşılaştırma için StringComparison.InvariantCulture kullanmanın birkaç nedeninden biri, kültürler arası aynı görüntülenmesi için sıralanan verilerin kalıcı hale getirilmesidir. Örneğin bir uygulamanın yanında, görüntülenecek bir sıralı tanımlayıcılar listesi içeren büyük bir veri dosyası varsa bu listeye ekleme yapmak sabit stil sıralama ile eklemeyi gerektirir.
Yöntem çağrınız için StringComparison üyesi seçme
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ı dahili tanımlayıcılar. XML ve HTTP gibi standartlardaki büyük/küçük harfe duyarlı tanımlayıcılar. Güvenlikle ilgili büyük/küçük harfe duyarlı ayarlar. |
Baytların tam olarak eşleştiği dilsel olmayan bir tanımlayıcı. | Ordinal |
Büyük/küçük harfe duyarsız iç tanımlayıcılar. XML ve HTTP gibi standartlardaki büyük/küçük harfe duyarsız tanımlayıcılar. Dosya yolları. Kayıt defteri anahtarları ve değerleri. Ortam değişkenleri. Kaynak tanımlayıcıları (örneğin, işleyici adları). Güvenlikle ilgili büyük/küçük harfe duyarsız ayarlar. |
Büyük/küçük harfle ilgisiz olan dilsel olmayan bir tanımlayıcı. | OrdinalIgnoreCase |
Kalıcı olan bazı dilsel veriler. Sabit bir sıralama düzeni gerektiren dilsel verinin görüntülenmesi. |
Dilsel olan ancak kültüre duyarlı olmayan veri. | InvariantCulture -veya- InvariantCultureIgnoreCase |
Kullanıcıya görüntülenen veri. Çoğu kullanıcı girişi. |
Yerel dilsel özellikleri gerektiren veriler. | CurrentCulture -veya- CurrentCultureIgnoreCase |
.NET'te yaygın dize karşılaştırma yöntemleri
Aşağıdaki bölümlerde, en yaygın olarak dize karşılaştırmaları için kullanılan yöntemler açıklanır.
String.Compare
Varsayılan yorum: StringComparison.CurrentCulture.
Dize yorumlamak için en önemli işlem olarak bu yöntem çağrılarının tüm örnekleri, dizelerin geçerli kültüre göre mi yoksa geçerli kültürden bağımsız (simgesel) olarak mı yorumlanacağını 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ı, aynı zamanda Compare bayrak sabit listesini kullanarak çok sayıda eşleştirme seçeneği (sıralı, boşluğu göz ardı ederek, kana türünü göz ardı ederek vb.) sunan bir CompareOptions yöntemi de içerir.
String.CompareTo
Varsayılan yorum: StringComparison.CurrentCulture.
Bu yöntem şu anda bir tür belirten bir aşırı yükleme sunmaz StringComparison . 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. Bir parametre seçeneği StringComparison sunmadığından, türlerin uygulanması genellikle kullanıcının oluşturucusunda bir StringComparer belirtmesine olanak tanır. Aşağıdaki örnek, sınıf oluşturucusu bir FileName
parametresi içeren bir StringComparer sınıfını tanımlar. Bu StringComparer nesnesi 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.
String sınıfı, 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ırma kullanır. Ancak, sıralı karşılaştırma yapmak isteseniz bile StringComparison türünü açıkça belirten bir aşırı yükleme çağırmanızı öneririz, çünkü bu, belirli bir dize yorumu için kodda arama yapmanızı kolaylaştırır.
String.ToUpper ve String.ToLower
Varsayılan yorum: StringComparison.CurrentCulture.
ve String.ToLower() yöntemlerini kullanırken String.ToUpper() dikkatli olun çünkü bir dizeyi büyük veya küçük harfe zorlamak genellikle büyük/küçük harfe bakılmaksızın dizeleri karşılaştırmak için küçük bir normalleştirme olarak kullanılır. Bu durumda, büyük/küçük harfe duyarsız bir karşılaştırma kullanmayı düşünün.
Aynı zamanda String.ToUpperInvariant ve String.ToLowerInvariant yöntemleri de mevcuttur. ToUpperInvariant, büyük/küçük harfi normalleştirmek için standart yöntemdir. StringComparison.OrdinalIgnoreCase kullanılarak yapılan karşılaştırmalar, davranışsal olarak iki çağrının birleşimidir: her iki dize bağımsız değişkeninde ToUpperInvariant'i çağırmak ve StringComparison.Ordinal kullanarak bir karşılaştırma yapmak.
Aşırı yüklemeler aynı zamanda, yöntemde kültürü temsil eden bir CultureInfo nesnesini geçirerek belirli bir kültürde büyük harfe ve küçük harfe dönüştürme için de kullanılabilir.
Char.ToUpper ve Char.ToLower
Varsayılan yorum: StringComparison.CurrentCulture.
ve Char.ToLower(Char) yöntemleri, Char.ToUpper(Char) önceki bölümde açıklanan ve String.ToLower() yöntemlerine benzer şekilde String.ToUpper() çalışır.
String.StartsWith ve String.EndsWith
Varsayılan yorum: StringComparison.CurrentCulture.
Varsayılan olarak, bu yöntemlerin ikisi de kültüre duyarlı bir karşılaştırma yapar. Özellikle, yazdırılmayan karakterleri yoksayabilirler.
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. Bir String.IndexOf parametresi içeren tüm String.LastIndexOf ve Char yöntemleri sıralı karşılaştırma yapar, ancak bir String.IndexOf parametresi içeren varsayılan String.LastIndexOf ve String yöntemleri kültüre duyarlı bir karşılaştırma yapar.
Eğer String.IndexOf(String) veya String.LastIndexOf(String) yöntemini çağırıp geçerli örnekte konumlandırılacak bir dizeye geçirirseniz, StringComparison türünü açıkça belirten bir aşırı yüklemeyi çağırmanızı öneririz. Bağımsız değişken içeren Char aşırı yüklemeler bir StringComparison tür belirtmenize izin vermez.
Dolaylı olarak dize karşılaştırması gerçekleştiren yöntemler
Merkezi işlem olarak dize karşılaştırmasına sahip olan dize olmayan bazı yöntemler StringComparer türünü kullanır. StringComparer sınıfı, StringComparer yöntemleri aşağıdaki türde dize karşılaştırması yapan StringComparer.Compare örneklerini döndüren altı statik özelliği içerir:
- Geçerli kültürü kullanarak kültüre duyarlı dize karşılaştırmaları. Bu StringComparer nesnesi, StringComparer.CurrentCulture özelliği tarafından döndürülür.
- Geçerli kültürü kullanarak büyük/küçük harfe duyarsız karşılaştırmalar. Bu StringComparer nesnesi, StringComparer.CurrentCultureIgnoreCase özelliği tarafından döndürülür.
- Sabit kültürün sözcük karşılaştırma kurallarını kullanarak kültüre duyarsız karşılaştırmalar. Bu StringComparer nesnesi, StringComparer.InvariantCulture özelliği tarafından döndürülür.
- Sabit kültürün sözcük karşılaştırma kurallarını kullanarak büyük/küçük harfe ve kültüre duyarsız karşılaştırmalar. Bu StringComparer nesnesi, StringComparer.InvariantCultureIgnoreCase özelliği tarafından döndürülür.
- Sıralı karşılaştırma. Bu StringComparer nesnesi, StringComparer.Ordinal özelliği tarafından döndürülür.
- Büyük/küçük harfe duyarsız sıralı karşılaştırma. Bu StringComparer nesnesi, StringComparer.OrdinalIgnoreCase özelliği tarafından döndürülür.
Array.Sort ve Array.BinarySearch
Varsayılan yorum: StringComparison.CurrentCulture.
Herhangi bir veriyi bir koleksiyonda depoladığınızda veya bir dosyadan veya veritabanından kalıcı hale getirilmiş veriyi bir koleksiyonun içine okuduğunuzda geçerli kültürün değiştirilmesi, koleksiyon içindeki sabitleri geçersiz kılabilir. Array.BinarySearch yöntemi, aranacak dizideki öğelerin zaten sıralı olduğunu varsayar. Array.Sort yöntemi, dizideki herhangi bir dize öğesini sıralamak için, ayrı ayrı öğeleri düzenlemek amacıyla String.Compare yöntemini çağırır. Kültüre duyarlı bir karşılaştırıcı kullanmak, eğer dizi sıralanana ve içerikleri aranana kadar geçen zaman arasında kültür değişirse tehlikeli olabilir. Örneğin aşağıdaki kodda depolama ve alma işlemleri, Thread.CurrentThread.CurrentCulture
özelliği tarafından dolaylı olarak sağlanan karşılaştırıcıda gerçekleşir. Eğer kültür StoreNames
ve DoesNameExist
arasında değişebilirse ve özellikle dizi içerikleri iki yöntem çağrısı arasında bir yerde kalıcı hale getirilirse, 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 yöntem görünür. Değişim kodu, iki örnekte Line A
ve Line B
olarak etiketlenen satırlarda 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
Eğer bu veriler kalıcı hale getirilirse ve kültürler arasında taşınırsa, ve kullanıcıya bu verileri sunmak için sıralama kullanılırsa, dilsel olarak daha iyi kullanıcı çıktısı için çalışan, ancak kültür değişikliklerinden etkilenmeyen StringComparison.InvariantCulture öğesini kullanmayı düşünebilirsiniz. Aşağıdaki örnek, diziyi sıralamak ve aramak üzere sabit kültürü kullanmak için ö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
Karma dizeleri, dizelerin karşılaştırılma şeklinden etkilenen bir işlemin ikinci bir örneğini sağlar.
Aşağıdaki örnek, Hashtable özelliği tarafından döndürülen StringComparer nesnesini geçirerek bir StringComparer.OrdinalIgnoreCase nesnesi oluşturur. StringComparer'dan türetilen bir StringComparer sınıfı IEqualityComparer arabirimini uyguladığından GetHashCode yöntemi, karma tablosundaki dizelerin karma 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