Ajánlott eljárások sztringek összehasonlítása a .NET-ben
A .NET széles körű támogatást nyújt a honosított és globalizált alkalmazások fejlesztéséhez, és megkönnyíti a jelenlegi vagy egy adott kultúra konvenciók alkalmazását olyan gyakori műveletek végrehajtásakor, mint a sztringek rendezése és megjelenítése. A sztringek rendezése és összehasonlítása azonban nem mindig kulturális szempontból érzékeny művelet. Az alkalmazások által belsőleg használt sztringeket például általában minden kultúrában azonos módon kell kezelni. Ha a kulturálisan független sztringadatok, például XML-címkék, HTML-címkék, felhasználónevek, fájlelérési utak és a rendszerobjektumok nevei úgy vannak értelmezve, mintha kultúraérzékenyek lennének, az alkalmazáskódok apró hibákra, gyenge teljesítményre és bizonyos esetekben biztonsági problémákra lehetnek kitéve.
Ez a cikk a .NET-ben a sztringek rendezési, összehasonlítási és burkolatkezelési módszereit vizsgálja, javaslatot tesz a megfelelő sztringkezelési módszer kiválasztására, és további információkat nyújt a sztringkezelési módszerekről.
sztringhasználat Javaslatok
Ha a .NET-tel fejleszt, kövesse ezeket a javaslatokat a sztringek összehasonlításakor.
Tipp.
A sztringgel kapcsolatos különböző metódusok összehasonlítást végeznek. Ilyenek például a következők: String.Equals, String.Compare, String.IndexOfés String.StartsWith.
- Használjon túlterheléseket, amelyek explicit módon határozzák meg a sztring-összehasonlítási szabályokat a sztringműveletek esetében. Ez általában egy metódus túlterhelésének meghívását foglalja magában, amely típusparaméterrel StringComparisonrendelkezik.
- Használja StringComparison.Ordinal vagy StringComparison.OrdinalIgnoreCase hasonlítsa össze biztonságos alapértelmezettként a kulturális és agnosztikus sztringek egyeztetését.
- Használjon összehasonlítást a StringComparison.OrdinalStringComparison.OrdinalIgnoreCase jobb teljesítmény érdekében.
- Olyan sztringműveleteket használjon, amelyek a StringComparison.CurrentCulture kimenet felhasználónak való megjelenítésekor alapulnak.
- Sztringműveletek CultureInfo.InvariantCulture helyett használjon nem nyelvi StringComparison.Ordinal vagy StringComparison.OrdinalIgnoreCase értékeket, ha az összehasonlítás nyelvi szempontból irreleváns (például szimbolikus).
- A metódus helyett a metódust String.ToUpperInvariant használja a String.ToLowerInvariant sztringek összehasonlításhoz való normalizálásakor.
- A metódus túlterhelésével String.Equals tesztelje, hogy két sztring egyenlő-e.
- A sztringek String.Compare rendezéséhez és String.CompareTo a metódusok használatával ne az egyenlőséget ellenőrizze.
- A nem sztringadatokat, például számokat és dátumokat a felhasználói felületen kulturális szempontból érzékeny formázással jelenítheti meg. A nem sztring típusú adatok sztring formában való megőrzéséhez használja a formázást az invariáns kultúrával .
Sztringek összehasonlítása esetén kerülje az alábbi eljárásokat:
- Ne használjon olyan túlterheléseket, amelyek nem explicit módon vagy implicit módon határozzák meg a sztring-összehasonlítási szabályokat a sztringműveletek esetében.
- A legtöbb esetben ne használjon sztringműveleteket StringComparison.InvariantCulture . A néhány kivétel egyike, ha nyelvileg jelentőséggel bíró, de kulturálisan agnosztikus adatokat őriz meg.
- Ne használja a String.Compare metódus túlterhelését CompareTo , és ne tesztelje a nulla visszatérési értéket annak megállapításához, hogy két sztring egyenlő-e.
Sztring-összehasonlítások explicit megadása
A .NET-ben a sztringmanipulálási módszerek többsége túlterhelt. Általában egy vagy több túlterhelés fogadja el az alapértelmezett beállításokat, míg mások nem fogadnak el alapértelmezett értékeket, és ehelyett meghatározzák a sztringek összehasonlításának vagy módosításának pontos módját. Az alapértelmezett értékekre nem támaszkodó metódusok többsége tartalmaz egy típusparamétert StringComparison, amely egy számbavétel, amely explicit módon határozza meg a sztringek összehasonlításának szabályait kultúra és eset szerint. Az alábbi táblázat az enumerálási StringComparison tagokat ismerteti.
StringComparison-tag | Leírás |
---|---|
CurrentCulture | Kis- és nagybetűket megkülönböztető összehasonlítást végez az aktuális kultúrával. |
CurrentCultureIgnoreCase | Kis- és nagybetűk érzéketlen összehasonlítását hajtja végre az aktuális kultúra használatával. |
InvariantCulture | Kis- és nagybetűket megkülönböztető összehasonlítást végez az invariáns kultúra használatával. |
InvariantCultureIgnoreCase | Kis- és nagybetűket nem érzékelyítő összehasonlítást végez az invariáns kultúra használatával. |
Ordinal | Ordinális összehasonlítást végez. |
OrdinalIgnoreCase | Kis- és nagybetűk érzéketlen összehasonlítása. |
A metódus például IndexOf , amely egy karakternek vagy sztringnek megfelelő objektumban String lévő részsztring indexét adja vissza, kilenc túlterheléssel rendelkezik:
- IndexOf(Char), IndexOf(Char, Int32)és IndexOf(Char, Int32, Int32), amely alapértelmezés szerint rendezési (kis- és nagybetűkre érzékeny és kultúraérzékeny) keresést hajt végre a sztringben egy karakterre.
- IndexOf(String), IndexOf(String, Int32)és IndexOf(String, Int32, Int32), amely alapértelmezés szerint a sztringben lévő részsztring kis- és nagybetűkre érzékeny és kultúraérzékeny keresését hajtja végre.
- IndexOf(String, StringComparison), IndexOf(String, Int32, StringComparison)és IndexOf(String, Int32, Int32, StringComparison), amelyek olyan típusú StringComparison paramétert tartalmaznak, amely lehetővé teszi az összehasonlítás formájának megadását.
Javasoljuk, hogy az alábbi okokból válasszon túlterhelést, amely nem használ alapértelmezett értékeket:
Egyes alapértelmezett paraméterekkel (amelyek a sztringpéldányban Char keresnek) túlterhelések végeznek sorszám-összehasonlítást, míg mások (amelyek a sztringpéldányban keresnek sztringet) kulturális szempontból érzékenyek. Nehéz megjegyezni, hogy melyik metódus melyik alapértelmezett értéket használja, és könnyen összekeverheti a túlterheléseket.
A metódushívások alapértelmezett értékeire támaszkodó kód szándéka nem egyértelmű. A következő példában, amely az alapértelmezett értékekre támaszkodik, nehéz megállapítani, hogy a fejlesztő valójában két sztring sorszámát vagy nyelvi összehasonlítását szánta-e, vagy a "https" és a "https" közötti kis- és nagybetűk közötti
url.Scheme
különbség okozhatja az egyenlőségi teszt visszatérésétfalse
.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
Általában azt javasoljuk, hogy olyan metódust hívjon meg, amely nem támaszkodik az alapértelmezett értékekre, mert egyértelművé teszi a kód szándékát. Ez pedig olvashatóbbá és könnyebben kezelhetővé teszi a kódot. Az alábbi példa az előző példával kapcsolatban felmerült kérdésekre ad választ. Egyértelművé teszi, hogy a rendszer a sorszám-összehasonlítást használja, és hogy a különbségeket figyelmen kívül hagyja.
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
A sztringek összehasonlításának részletei
A sztringek összehasonlítása számos sztringgel kapcsolatos művelet középpontjában áll, különösen az egyenlőség rendezése és tesztelése. Sztringek meghatározott sorrendben rendezve: Ha a "my" a "sztring" előtt jelenik meg a sztringek rendezett listájában, a "my" értéknek kisebbnek vagy egyenlőnek kell lennie a "sztring" értéknél. Emellett az összehasonlítás implicit módon definiálja az egyenlőséget. Az összehasonlító művelet nullát ad vissza az általa egyenlőnek ítélt sztringekhez. Jó értelmezés, hogy egyik sztring sem kisebb, mint a másik. A sztringeket tartalmazó legérthetőbb műveletek közé tartozik az egyik vagy mindkét eljárás: egy másik sztringgel való összehasonlítás és egy jól definiált rendezési művelet végrehajtása.
Feljegyzés
Letöltheti a Rendezési súlytáblákat, a Windows operációs rendszerek rendezési és összehasonlítási műveleteihez használt karaktersúlyokra vonatkozó információkat tartalmazó szövegfájlokat, valamint a Linux és macOS rendszerekhez készült rendezési súlytáblázat legújabb verzióját, az Alapértelmezett Unicode rendezési elem táblát. A linuxos és macOS rendszerű rendezési súlytábla konkrét verziója a rendszeren telepített Unicode-kódtárak nemzetközi összetevőinek verziójától függ. Az ICU-verziókról és az általuk implementálható Unicode-verziókról további információt az ICU letöltése című témakörben talál.
Az egyenlőségi vagy rendezési sorrend két sztringjének kiértékelése azonban nem eredményez egyetlen, helyes eredményt; az eredmény a sztringek összehasonlításához használt feltételektől függ. Az aktuális kultúra vagy az invariáns kultúra (az angol nyelvre épülő területi-agnosztikus kultúra) keretezési és rendezési konvencióin alapuló sztring-összehasonlítások eltérő eredményeket eredményezhetnek.
Emellett a .NET különböző verzióit használó, illetve a .NET-et különböző operációs rendszereken vagy operációsrendszer-verziókon használó sztring-összehasonlítások eltérő eredményeket adhatnak vissza. További információ: Sztringek és Unicode Standard.
Az aktuális kultúrát használó sztring-összehasonlítások
Az egyik feltétel az aktuális kultúra konvencióit használja a sztringek összehasonlítása során. Az aktuális kultúrán alapuló összehasonlítások a szál aktuális kultúráját vagy területi beállítását használják. Ha a kultúrát nem a felhasználó állítja be, az alapértelmezés szerint az operációs rendszer beállítása. Mindig olyan összehasonlításokat kell használnia, amelyek a jelenlegi kultúrán alapulnak, amikor az adatok nyelvi szempontból relevánsak, és amikor azok a kultúra szempontjából érzékeny felhasználói interakciókat tükrözik.
A .NET-ben azonban az összehasonlítás és a burkolat viselkedése megváltozik, amikor a kultúra megváltozik. Ez akkor fordul elő, ha egy alkalmazás olyan számítógépen fut, amely más kultúrával rendelkezik, mint az a számítógép, amelyen az alkalmazást fejlesztették, vagy amikor a végrehajtó szál megváltoztatja a kultúráját. Ez a viselkedés szándékos, de sok fejlesztő számára nem nyilvánvaló. Az alábbi példa az amerikai angol ("en-US") és a svéd ("sv-Standard kiadás") kultúrák közötti rendezési sorrend különbségeit szemlélteti. Vegye figyelembe, hogy az "ångström", a "Windows" és a "Visual Studio" szavak a rendezett sztringtömbök különböző pozícióiban jelennek meg.
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
Az aktuális kultúrát használó kis- és nagybetűk érzéketlen összehasonlításai megegyeznek a kultúraérzékeny összehasonlításokkal, azzal a különbségtel, hogy figyelmen kívül hagyják a szál aktuális kultúrája által diktált kis- és nagybetűket. Ez a viselkedés rendezési sorrendben is nyilvánulhat meg.
Az alábbi módszerek alapértelmezetten az aktuális kulturális szemantikát használó összehasonlításokat használják:
- String.Compare túlterhelések, amelyek nem tartalmaznak paramétert StringComparison .
- String.CompareTo Túlterhelés.
- Az alapértelmezett String.StartsWith(String) metódus és a String.StartsWith(String, Boolean, CultureInfo) paraméterrel
null
CultureInfo rendelkező metódus. - Az alapértelmezett String.EndsWith(String) metódus és a String.EndsWith(String, Boolean, CultureInfo) paraméterrel
null
CultureInfo rendelkező metódus. - String.IndexOf túlterhelések, amelyek keresési paraméterként fogadnak el, String és amelyek nem rendelkeznek paraméterrel StringComparison .
- String.LastIndexOf túlterhelések, amelyek keresési paraméterként fogadnak el, String és amelyek nem rendelkeznek paraméterrel StringComparison .
Mindenesetre azt javasoljuk, hogy olyan túlterhelést hívjon meg, amelynek paramétere StringComparison egyértelművé teszi a metódushívás szándékát.
Finom és nem annyira finom hibák akkor jelentkezhetnek, ha a nem nyelvi sztringadatokat nyelvileg értelmezik, vagy ha egy adott kultúrából származó sztringadatokat egy másik kultúra konvenciói alapján értelmeznek. A canonical példa a török-I probléma.
Az "i" (\u0069) karakter az "I" (\u0049) karakter kisbetűs változata. Ez a casing szabály gyorsan az alapértelmezetté válik egy ilyen kultúrában programozó személy számára. A török ("tr-TR") ábécé azonban tartalmaz egy "I with a dot" (İ) karaktert (\u0130), amely az "i" nagybetűs verziója. A török tartalmaz egy kisbetűs "i without a dot" (ı) (\u0131) karaktert is, amely az "I" nagybetűt használja. Ez a viselkedés az azerbajdzsáni ("az") kultúrában is előfordul.
Ezért az "i" vagy az "I" nagybetűsítésével kapcsolatos feltételezések nem érvényesek minden kultúrában. Ha a sztring-összehasonlítási rutinokhoz az alapértelmezett túlterheléseket használja, akkor azok a kultúrák közötti eltérésnek lesznek kitéve. Ha az összehasonlítandó adatok nem nyelvi jellegűek, az alapértelmezett túlterhelések nem kívánt eredményeket eredményezhetnek, mivel az alábbi kísérlet a "bill" és a "BILL" sztringek kis- és nagybetűk érzéketlen összehasonlítását mutatja be.
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
Ez az összehasonlítás jelentős problémákat okozhat, ha a kultúrát véletlenül használják biztonsági szempontból érzékeny beállításokban, ahogyan az alábbi példában is látható. Egy metódushívás, például IsFileURI("file:")
akkor ad true
vissza, ha a jelenlegi kultúra amerikai angol, de false
ha a jelenlegi kultúra török. Így a török rendszereken valaki megkerülheti a "FILE:" kezdetű, kis- és nagybetűkkel nem érzéketlen URI-khoz való hozzáférést megakadályozó biztonsági intézkedéseket.
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
Ebben az esetben, mivel a "file:" nem nyelvi, kulturális érzéketlen azonosítóként van értelmezve, a kódot inkább az alábbi példában látható módon kell megírni:
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
Sorszámi sztringműveletek
A metódushívásban szereplő StringComparison.Ordinal érték megadása StringComparison.OrdinalIgnoreCase nem nyelvi összehasonlítást jelent, amelyben a természetes nyelvek jellemzői figyelmen kívül lesznek hagyva. Az ezekkel az StringComparison értékekkel meghívott metódusok a sztringműveleteket egyszerű bájt-összehasonlításokra alapozza a kultúra által paraméterezett casing vagy ekvivalenciatáblák helyett. Ez a megközelítés a legtöbb esetben a sztringek tervezett értelmezéséhez illeszkedik, miközben a kód gyorsabb és megbízhatóbb.
Az ordinális összehasonlítások olyan sztring-összehasonlítások, amelyekben az egyes sztringek minden bájtját nyelvi értelmezés nélkül hasonlítják össze; Például a "windows" nem egyezik a "Windows" értékkel. Ez lényegében a C futtatókörnyezet strcmp
függvény hívása. Ezt az összehasonlítást akkor használja, ha a környezet azt diktálja, hogy a sztringek pontosan egyezzenek meg, vagy konzervatív egyeztetési szabályzatot követeljen meg. Emellett a sorszámos összehasonlítás a leggyorsabb összehasonlítási művelet, mivel nem alkalmaz nyelvi szabályokat az eredmény meghatározásakor.
A .NET-sztringek beágyazott null karaktereket (és más nem nyomtatható karaktereket) tartalmazhatnak. A sorszám- és kultúraérzékeny összehasonlítás (beleértve az invariáns kultúrát használó összehasonlításokat is) egyik legtisztább különbsége a beágyazott null karakterek sztringben való kezelésére vonatkozik. Ezeket a karaktereket a rendszer figyelmen kívül hagyja, amikor a String.Compare kulturális szempontból érzékeny összehasonlításokat és String.Equals metódusokat használja (beleértve az invariáns kultúrát használó összehasonlításokat is). Ennek eredményeképpen a beágyazott null karaktereket tartalmazó sztringek egyenlőnek tekinthetők azokkal a sztringekkel, amelyek nem. A beágyazott nem nyomtatható karakterek kihagyhatók a sztring-összehasonlító módszerek, például String.StartsWitha .
Fontos
Bár a sztring-összehasonlító metódusok figyelmen kívül hagyják a beágyazott null karaktereket, a sztringkeresési módszerek, például String.Containsa , String.EndsWith, String.IndexOfString.LastIndexOf, és String.StartsWith nem.
Az alábbi példa az "Aa" sztring kultúraérzékeny összehasonlítását hajtja végre egy hasonló sztringgel, amely több beágyazott null karaktert tartalmaz az "A" és az "a" között, és megmutatja, hogy a két sztring hogyan tekinthető egyenlőnek:
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
A sztringek azonban nem tekinthetők egyenlőnek a sorszám-összehasonlítás használatakor, ahogy az alábbi példa is mutatja:
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
A kis- és nagybetűk érzéketlen összehasonlítása a következő legkonzervatívabb megközelítés. Ezek az összehasonlítások figyelmen kívül hagyják a legtöbb burkolatot; például a "windows" egyezik a "Windows" értékkel. Az ASCII-karakterek kezelésekor ez a szabályzat egyenértékű StringComparison.Ordinalazzal a különbséggel, hogy figyelmen kívül hagyja a szokásos ASCII-burkolatot. Ezért az [A, Z] (\u0041-\u005A) összes karaktere megegyezik az [a,z] (\u0061-\007A) megfelelő karakterével. Az ASCII-tartományon kívüli burkolatok az invariáns kultúra tábláit használják. Ezért a következő összehasonlítás:
string.Compare(strA, strB, StringComparison.OrdinalIgnoreCase);
String.Compare(strA, strB, StringComparison.OrdinalIgnoreCase)
egyenértékű az összehasonlítással (de gyorsabb), mint:
string.Compare(strA.ToUpperInvariant(), strB.ToUpperInvariant(), StringComparison.Ordinal);
String.Compare(strA.ToUpperInvariant(), strB.ToUpperInvariant(), StringComparison.Ordinal)
Ezek az összehasonlítások még mindig nagyon gyorsak.
Mindkettőt StringComparison.Ordinal , és StringComparison.OrdinalIgnoreCase használja közvetlenül a bináris értékeket, és a legjobban alkalmas az egyeztetésre. Ha nem biztos az összehasonlítási beállításokban, használja a két érték egyikét. Mivel azonban bájtonkénti összehasonlítást végeznek, nem nyelvi rendezési sorrend (például angol szótár) szerint rendeznek, hanem bináris rendezési sorrend szerint. Az eredmények a legtöbb környezetben furcsának tűnhetnek, ha a felhasználók megjelennek.
Az ordinális szemantika az argumentumot nem tartalmazó túlterhelések (beleértve az egyenlőségi operátortStringComparison) alapértelmezett String.Equals értéke. Mindenesetre azt javasoljuk, hogy egy paraméterrel rendelkező StringComparison túlterhelést hívjon meg.
Az invariáns kultúrát használó sztringműveletek
Az invariáns kultúrával való összehasonlítás a CompareInfo statikus CultureInfo.InvariantCulture tulajdonság által visszaadott tulajdonságot használja. Ez a viselkedés minden rendszeren ugyanaz; a tartományon kívüli karaktereket lefordítja egyenértékű invariáns karakterekké. Ez a szabályzat hasznos lehet a különböző kultúrák sztring-viselkedésének fenntartásához, de gyakran váratlan eredményt ad.
Az invariáns kultúrával való kis- és nagybetűs összehasonlítások a statikus CultureInfo.InvariantCulture tulajdonság által visszaadott statikus CompareInfo tulajdonságot is használják összehasonlítási információkhoz. A lefordított karakterek közötti különbségeket a rendszer figyelmen kívül hagyja.
Az ASCII-sztringeken azonos módon használt StringComparison.InvariantCulture és StringComparison.Ordinal működő összehasonlítások. Azonban olyan nyelvi döntéseket hoz, StringComparison.InvariantCulture amelyek nem feltétlenül megfelelőek a bájthalmazként értelmezendő sztringekhez. Az CultureInfo.InvariantCulture.CompareInfo
objektum lehetővé teszi, hogy a Compare metódus bizonyos karakterkészleteket egyenértékűként értelmezzen. Például a következő egyenértékűség érvényes az invariáns kultúrában:
InvariantCulture: a + ̊ = å
A LATIN KIS BETŰ A karakter "a" (\u0061), ha a "+ " ̊" (\u030a) karakter fölötti KOMBINÁLT GYŰRŰ mellett van, akkor a LATIN KIS BETŰ A KARAKTER "å" karakter fölötti gyűrűvel (\u00e5) értelmezve. Ahogy az alábbi példa is mutatja, ez a viselkedés eltér az ordinális összehasonlítástól.
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
Ha fájlneveket, cookie-kat vagy bármi mást értelmez, ahol egy kombináció, például az "å" jelenhet meg, adinális összehasonlítások továbbra is a legátláthatóbb és legilleszthetőbb viselkedést kínálják.
Egyensúlyban az invariáns kultúra kevés olyan tulajdonsággal rendelkezik, amelyek hasznossá teszik az összehasonlítást. Nyelvi szempontból releváns összehasonlítást végez, ami megakadályozza, hogy teljes szimbolikus egyenértékűséget garantáljon, de nem ez a választás a kulturális környezetben való megjelenítéshez. Az összehasonlítás néhány oka StringComparison.InvariantCulture közé tartozik a rendezett adatok megőrzése a kulturálisan azonos megjelenítéshez. Ha például egy nagyméretű adatfájl, amely egy alkalmazáshoz tartozó rendezetlen azonosítók listáját tartalmazza, a listához való hozzáadáshoz invariáns stílusú rendezés szükséges.
StringComparison-tag kiválasztása a metódushíváshoz
Az alábbi táblázat a szemantikai sztringkörnyezet és az enumerálási StringComparison tag leképezését ismerteti:
Adatok | Működés | Megfelelő System.StringComparison Érték |
---|---|---|
Kis- és nagybetűket megkülönböztető belső azonosítók. Kis- és nagybetűket megkülönböztető azonosítók olyan szabványokban, mint az XML és a HTTP. Kis- és nagybetűkre vonatkozó biztonsági beállítások. |
Nem nyelvi azonosító, ahol a bájtok pontosan egyeznek. | Ordinal |
Kis- és nagybetűket nem megkülönböztető belső azonosítók. Kis- és nagybetűket nem megkülönböztető azonosítók olyan szabványokban, mint az XML és a HTTP. Fájl elérési útjai. Beállításkulcsok és értékek. Környezeti változók. Erőforrás-azonosítók (például leírónevek). Kis- és nagybetűkkel kapcsolatos biztonsági beállítások. |
Nem nyelvi azonosító, ahol az eset irreleváns. | OrdinalIgnoreCase |
Néhány megőrzött, nyelvi szempontból releváns adat. Rögzített rendezési sorrendet igénylő nyelvi adatok megjelenítése. |
Kulturálisan agnosztikus adatok, amelyek még mindig nyelvi szempontból relevánsak. | InvariantCulture -vagy- InvariantCultureIgnoreCase |
A felhasználó számára megjelenített adatok. A legtöbb felhasználói bemenet. |
Helyi nyelvi szokásokat igénylő adatok. | CurrentCulture -vagy- CurrentCultureIgnoreCase |
Gyakori sztring-összehasonlító módszerek a .NET-ben
Az alábbi szakaszok a sztringek összehasonlítására leggyakrabban használt módszereket ismertetik.
String.Compare
Alapértelmezett értelmezés: StringComparison.CurrentCulture.
Mivel a művelet a sztringértelmezés középpontjában áll, a metódushívások minden példányát meg kell vizsgálni annak megállapításához, hogy a sztringeket a jelenlegi kultúra szerint kell-e értelmezni, vagy (szimbolikusan) el kell-e bontani a kultúrától. Általában ez az utóbbi, és inkább összehasonlítást StringComparison.Ordinal kell használni.
A System.Globalization.CompareInfo tulajdonság által CultureInfo.CompareInfo visszaadott osztály olyan metódust Compare is tartalmaz, amely a jelző számbavétele révén CompareOptions számos egyeztetési lehetőséget biztosít (sorszám, üres terület figyelmen kívül hagyása, kana típus figyelmen kívül hagyása stb.).
String.CompareTo
Alapértelmezett értelmezés: StringComparison.CurrentCulture.
Ez a metódus jelenleg nem kínál túlterhelést, amely típust StringComparison határoz meg. Ezt a metódust általában az ajánlott String.Compare(String, String, StringComparison) űrlapra lehet konvertálni.
A metódust IComparable megvalósító típusok és IComparable<T> interfészek implementálják ezt a módszert. Mivel nem kínál paramétert StringComparison , a implementálási típusok gyakran lehetővé teszik, hogy a felhasználó konstruktorában adjon meg egy paramétert StringComparer . Az alábbi példa egy olyan osztályt FileName
határoz meg, amelynek osztálykonstruktora tartalmaz egy paramétert StringComparer . Ezt az StringComparer objektumot ezután használja a FileName.CompareTo
metódus.
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
Alapértelmezett értelmezés: StringComparison.Ordinal.
Az String osztály lehetővé teszi az egyenlőség tesztelését a statikus vagy példánymetódus Equals túlterhelésének meghívásával, vagy a statikus egyenlőségi operátor használatával. A túlterhelések és az operátorok alapértelmezés szerint az ordinális összehasonlítást használják. Továbbra is azt javasoljuk azonban, hogy túlterhelést hívjon, amely explicit módon meghatározza a StringComparison típust, még akkor is, ha egy sorszám-összehasonlítást szeretne végrehajtani; ez megkönnyíti a kód keresését egy bizonyos sztringértelmezéshez.
String.ToUpper és String.ToLower
Alapértelmezett értelmezés: StringComparison.CurrentCulture.
Ügyeljen arra, hogy a metódusok és String.ToLower() a String.ToUpper() metódusok használata során a sztringeket kis- vagy nagybetűkre kényszerítse, mert a sztringek kis normalizálása a sztringek kisbetűs összehasonlítása esetén, esettől függetlenül. Ha igen, fontolja meg a kis- és nagybetűk érzéketlen összehasonlítását.
A String.ToUpperInvariant módszerek és String.ToLowerInvariant a metódusok is elérhetők. ToUpperInvariant a kis- és nagybetűk normalizálásának szokásos módja. A használt StringComparison.OrdinalIgnoreCase összehasonlítások viselkedési szempontból két hívás összetétele: mindkét sztringargumentum meghívása ToUpperInvariant és az összehasonlítás a használatával StringComparison.Ordinal.
A túlterhelések egy adott kultúrában nagy- és kisbetűssé alakíthatók úgy is, hogy átadnak egy CultureInfo objektumot, amely az adott kultúrát jelöli a metódusnak.
Char.ToUpper és Char.ToLower
Alapértelmezett értelmezés: StringComparison.CurrentCulture.
A Char.ToUpper(Char) metódusok és Char.ToLower(Char) a String.ToUpper()String.ToLower() módszerek az előző szakaszban leírthoz hasonlóan működnek.
String.StartsWith és String.EndsWith
Alapértelmezett értelmezés: StringComparison.CurrentCulture.
Alapértelmezés szerint mindkét módszer kultúraérzékeny összehasonlítást végez. Különösen figyelmen kívül hagyhatják a nem nyomtatható karaktereket.
String.IndexOf és String.LastIndexOf
Alapértelmezett értelmezés: StringComparison.CurrentCulture.
Hiányzik a konzisztencia abban, hogy a metódusok alapértelmezett túlterhelései hogyan hajtanak végre összehasonlításokat. A paramétert tartalmazó összes String.IndexOf és String.LastIndexOf metódus végrehajtja a sorszám-összehasonlítást, de az alapértelmezett String.IndexOf és String.LastIndexOf a paramétert String tartalmazó metódusok kultúraérzékeny összehasonlítást végeznek.Char
Ha meghívja a String.IndexOf(String) metódust, String.LastIndexOf(String) és egy sztringet ad meg az aktuális példányban való kereséshez, javasoljuk, hogy a típust explicit módon meghatározó StringComparison túlterhelést hívjon meg. Az argumentumot Char tartalmazó túlterhelések nem teszik lehetővé a típus megadását StringComparison .
Sztring-összehasonlítást közvetetten végző metódusok
Egyes nem sztringalapú metódusok, amelyek központi műveletként sztring-összehasonlítással rendelkeznek, a típust használják StringComparer . Az StringComparer osztály hat statikus tulajdonságot tartalmaz, amelyek olyan példányokat ad vissza StringComparer , amelyek StringComparer.Compare metódusai a következő sztring-összehasonlításokat hajtják végre:
- Kultúraérzékeny sztringek összehasonlítása az aktuális kultúrával. Ezt StringComparer az objektumot a StringComparer.CurrentCulture tulajdonság adja vissza.
- Kis- és nagybetűk érzéketlen összehasonlítása a jelenlegi kultúrával. Ezt StringComparer az objektumot a StringComparer.CurrentCultureIgnoreCase tulajdonság adja vissza.
- Kultúra-érzéketlen összehasonlítások az invariáns kultúra összehasonlítási szabályainak használatával. Ezt StringComparer az objektumot a StringComparer.InvariantCulture tulajdonság adja vissza.
- Kis- és nagybetűk érzéketlen és kulturális érzéketlen összehasonlításai az invariáns kultúra összehasonlító szabályainak használatával. Ezt StringComparer az objektumot a StringComparer.InvariantCultureIgnoreCase tulajdonság adja vissza.
- A sorszámok összehasonlítása. Ezt StringComparer az objektumot a StringComparer.Ordinal tulajdonság adja vissza.
- Kis- és nagybetűk érzéketlen összehasonlítása. Ezt StringComparer az objektumot a StringComparer.OrdinalIgnoreCase tulajdonság adja vissza.
Array.Sort and Array.BinarySearch
Alapértelmezett értelmezés: StringComparison.CurrentCulture.
Ha egy gyűjteményben tárol adatokat, vagy egy fájlból vagy adatbázisból származó tárolt adatokat olvas be gyűjteménybe, az aktuális kultúra váltása érvénytelenítheti a gyűjteményben lévő állandókat. A Array.BinarySearch metódus feltételezi, hogy a keresendő tömb elemei már rendezve vannak. A tömb bármely sztringelemének rendezéséhez a Array.Sort metódus meghívja a metódust String.Compare az egyes elemek rendezésére. A kultúraérzékeny összehasonlító használata veszélyes lehet, ha a kultúra a tömb rendezése és tartalma között változik. Az alábbi kódban például a tárolás és a lekérés a tulajdonság által Thread.CurrentThread.CurrentCulture
implicit módon biztosított összehasonlítón működik. Ha a kultúra megváltozhat a hívás és StoreNames
DoesNameExist
a – különösen akkor, ha a tömb tartalma valahol a két metódushívás között megmarad –, a bináris keresés sikertelen lehet.
// 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
Az alábbi példában egy javasolt változat jelenik meg, amely ugyanazt a rendezési (kulturális érzéketlenség) összehasonlító módszert használja a tömb rendezéséhez és kereséséhez. A változáskód a címkézett Line A
sorokban és Line B
a két példában is megjelenik.
// 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
Ha ezek az adatok megmaradnak és átkerülnek a kultúrák között, és a rendszer rendezéssel jeleníti meg ezeket az adatokat a felhasználónak, érdemes lehet használni StringComparison.InvariantCulture, amely nyelvileg működik a jobb felhasználói teljesítmény érdekében, de a kultúra változásai nem érintik. Az alábbi példa módosítja az előző két példát, hogy az invariáns kultúrát használja a tömb rendezéséhez és kereséséhez.
// 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
Példák gyűjteményekre: Hashtable konstruktor
A kivonatolási sztringek egy második példát nyújtanak egy olyan műveletre, amelyet a sztringek összehasonlítása érint.
Az alábbi példa a tulajdonság által StringComparer.OrdinalIgnoreCase visszaadott objektum átadásával StringComparer példányosít egy Hashtable objektumot. Mivel egy, az IEqualityComparer interfész implementálásából StringComparer származó osztályStringComparer, a metódusa GetHashCode a kivonattáblában lévő sztringek kivonatkódjának kiszámítására szolgál.
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