Globalizáció
A globalizáció magában foglalja egy olyan, világra kész alkalmazás tervezését és fejlesztését, amely támogatja a honosított felületeket és a regionális adatokat a több kultúrában lévő felhasználók számára. A tervezési fázis megkezdése előtt meg kell határoznia, hogy az alkalmazás mely kultúrákat támogatja. Bár egy alkalmazás alapértelmezés szerint egyetlen kultúrát vagy régiót céloz meg, megtervezheti és megírhatja, hogy könnyen kiterjeszthető legyen más kultúrák vagy régiók felhasználóira.
Fejlesztőkként mindannyian feltételezzük a felhasználói felületeket és a kultúránk által létrehozott adatokat. Például egy angolul beszélő fejlesztő esetében a Egyesült Államok a dátum- és időadatok sztringként MM/dd/yyyy hh:mm:ss
való szerializálása teljesen ésszerűnek tűnik. Ha azonban a sztringet egy másik kultúrában lévő rendszeren deszerializálja, az valószínűleg kivételt FormatException okoz, vagy pontatlan adatokat eredményez. A globalizáció lehetővé teszi az ilyen kultúraspecifikus feltételezések azonosítását és annak biztosítását, hogy azok ne befolyásolják az alkalmazás kialakítását vagy kódját.
Ez a cikk a sztringek, a dátum- és időértékek, valamint a numerikus értékek globalizált alkalmazásokban való kezelése során megfontolandó főbb problémákat és az ajánlott eljárásokat ismerteti.
Sztringek
A karakterek és sztringek kezelése a globalizáció központi témája, mivel minden kultúra vagy régió különböző karaktereket és karakterkészleteket használhat, és másképp rendezheti őket. Ez a szakasz a sztringek globalizált alkalmazásokban való használatára vonatkozó javaslatokat tartalmaz.
A Unicode belső használata
A .NET alapértelmezés szerint Unicode-sztringeket használ. A Unicode-sztringek nulla, egy vagy több Char objektumból állnak, amelyek mindegyike egy UTF-16 kódegységet jelöl. A világon minden használatban lévő karakterben szinte minden karakternek van Unicode-reprezentációja.
Számos alkalmazás és operációs rendszer, köztük a Windows operációs rendszer is használhat kódlapokat a karakterkészletek megjelenítéséhez. A kódlapok általában tartalmazzák a standard ASCII-értékeket a 0x00 és 0x7F között, és más karaktereket képeznek le a 0x80 és 0xFF fennmaradó értékeire. A 0x80 és a 0xFF közötti értékek értelmezése az adott kódlaptól függ. Emiatt lehetőség szerint kerülnie kell a globalizált alkalmazások kódlapjainak használatát.
Az alábbi példa a kódlapadatok értelmezésének veszélyeit mutatja be, ha a rendszer alapértelmezett kódlapja eltér attól a kódlaptól, amelyen az adatokat mentették. (A forgatókönyv szimulálásához a példa kifejezetten különböző kódlapokat határoz meg.) Először is a példa egy tömböt határoz meg, amely a görög ábécé nagybetűs karaktereiből áll. A 737-as kódlap (más néven MS-DOS görög) használatával bájttömbbe kódolja őket, és fájlba menti a bájttömböt. Ha a fájl lekérése és a bájttömb dekódolása a 737-as kódlap használatával történik, az eredeti karakterek vissza lesznek állítva. Ha azonban a fájl lekérése és a bájttömb dekódolása az 1252-es kódlappal történik (vagy a Windows-1252, amely a latin ábécében szereplő karaktereket jelöli), az eredeti karakterek elvesznek.
using System;
using System.IO;
using System.Text;
public class Example
{
public static void CodePages()
{
// Represent Greek uppercase characters in code page 737.
char[] greekChars =
{
'Α', 'Β', 'Γ', 'Δ', 'Ε', 'Ζ', 'Η', 'Θ',
'Ι', 'Κ', 'Λ', 'Μ', 'Ν', 'Ξ', 'Ο', 'Π',
'Ρ', 'Σ', 'Τ', 'Υ', 'Φ', 'Χ', 'Ψ', 'Ω'
};
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
Encoding cp737 = Encoding.GetEncoding(737);
int nBytes = cp737.GetByteCount(greekChars);
byte[] bytes737 = new byte[nBytes];
bytes737 = cp737.GetBytes(greekChars);
// Write the bytes to a file.
FileStream fs = new FileStream(@".\\CodePageBytes.dat", FileMode.Create);
fs.Write(bytes737, 0, bytes737.Length);
fs.Close();
// Retrieve the byte data from the file.
fs = new FileStream(@".\\CodePageBytes.dat", FileMode.Open);
byte[] bytes1 = new byte[fs.Length];
fs.Read(bytes1, 0, (int)fs.Length);
fs.Close();
// Restore the data on a system whose code page is 737.
string data = cp737.GetString(bytes1);
Console.WriteLine(data);
Console.WriteLine();
// Restore the data on a system whose code page is 1252.
Encoding cp1252 = Encoding.GetEncoding(1252);
data = cp1252.GetString(bytes1);
Console.WriteLine(data);
}
}
// The example displays the following output:
// ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩ
// €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’""•–—
Imports System.IO
Imports System.Text
Module Example
Public Sub CodePages()
' Represent Greek uppercase characters in code page 737.
Dim greekChars() As Char = {"Α"c, "Β"c, "Γ"c, "Δ"c, "Ε"c, "Ζ"c, "Η"c, "Θ"c,
"Ι"c, "Κ"c, "Λ"c, "Μ"c, "Ν"c, "Ξ"c, "Ο"c, "Π"c,
"Ρ"c, "Σ"c, "Τ"c, "Υ"c, "Φ"c, "Χ"c, "Ψ"c, "Ω"c}
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance)
Dim cp737 As Encoding = Encoding.GetEncoding(737)
Dim nBytes As Integer = CInt(cp737.GetByteCount(greekChars))
Dim bytes737(nBytes - 1) As Byte
bytes737 = cp737.GetBytes(greekChars)
' Write the bytes to a file.
Dim fs As New FileStream(".\CodePageBytes.dat", FileMode.Create)
fs.Write(bytes737, 0, bytes737.Length)
fs.Close()
' Retrieve the byte data from the file.
fs = New FileStream(".\CodePageBytes.dat", FileMode.Open)
Dim bytes1(CInt(fs.Length - 1)) As Byte
fs.Read(bytes1, 0, CInt(fs.Length))
fs.Close()
' Restore the data on a system whose code page is 737.
Dim data As String = cp737.GetString(bytes1)
Console.WriteLine(data)
Console.WriteLine()
' Restore the data on a system whose code page is 1252.
Dim cp1252 As Encoding = Encoding.GetEncoding(1252)
data = cp1252.GetString(bytes1)
Console.WriteLine(data)
End Sub
End Module
' The example displays the following output:
' ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩ
' €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’""•–—
A Unicode használata biztosítja, hogy ugyanazok a kódegységek mindig ugyanarra a karakterre legyen leképezve, és hogy ugyanazok a karakterek mindig ugyanarra a bájttömbre lesznek megfeleltetve.
Erőforrásfájlok használata
Még ha egy olyan alkalmazást is fejleszt, amely egyetlen kultúrát vagy régiót céloz meg, akkor is érdemes erőforrásfájlokat használnia a felhasználói felületen megjelenő sztringek és egyéb erőforrások tárolására. Soha ne vegye fel őket közvetlenül a kódba. Az erőforrásfájlok használatának számos előnye van:
- Az összes sztring egyetlen helyen található. Nem kell a forráskódban keresnie egy adott nyelvhez vagy kultúrához módosítandó sztringek azonosításához.
- Nincs szükség sztringek duplikálására. Az erőforrásfájlokat nem használó fejlesztők gyakran definiálják ugyanazt a sztringet több forráskódfájlban. Ez a duplikáció növeli annak valószínűségét, hogy egy sztring módosításakor egy vagy több példány figyelmen kívül marad.
- Nem sztring típusú erőforrásokat, például képeket vagy bináris adatokat is belefoglalhat az erőforrásfájlba, ahelyett, hogy különálló fájlban tárolné őket, így könnyen lekérhetők.
Az erőforrásfájlok használata különösen előnyös, ha honosított alkalmazást hoz létre. Amikor erőforrásokat helyez üzembe a műholdas szerelvényekben, a közös nyelvi futtatókörnyezet automatikusan kiválaszt egy kultúrának megfelelő erőforrást a felhasználó aktuális felhasználói felületi kultúrája alapján, a CultureInfo.CurrentUICulture tulajdonság által meghatározott módon. Ha megfelelő kulturális erőforrást ad meg, és megfelelően példányosít egy ResourceManager objektumot, vagy erősen gépelt erőforrásosztályt használ, a futtatókörnyezet kezeli a megfelelő erőforrások lekérésének részleteit.
További információ az erőforrásfájlok létrehozásáról: Erőforrásfájlok létrehozása. A műholdas szerelvények létrehozásával és üzembe helyezésével kapcsolatos információkért lásd : Műholdas szerelvények létrehozása és erőforrások csomagolása és üzembe helyezése.
Sztringek keresése és összehasonlítása
Amikor csak lehetséges, a sztringeket teljes sztringekként kell kezelnie ahelyett, hogy önálló karaktersorozatként kezelné őket. Ez különösen fontos az alsztringek rendezésekor vagy keresésekor, hogy megelőzze a kombinált karakterek elemzésével kapcsolatos problémákat.
Tipp.
Az osztály használatával a StringInfo sztring egyes karakterei helyett a szövegelemeket is használhatja.
A sztringkeresésekben és -összehasonlításokban gyakori hiba, hogy a sztringet karakterek gyűjteményeként kezeli, amelyek mindegyikét egy Char objektum jelöli. Valójában egyetlen karaktert egy, két vagy több Char objektum alkothat. Ezek a karakterek leggyakrabban olyan kultúrák sztringjeiben találhatók, amelyek ábécéi a Unicode egyszerű latin karaktertartományán kívüli karakterekből állnak (U+0021–U+007E). Az alábbi példa egy sztringben próbálja megtalálni a LATIN NAGYBETŰS A WITH GRAVE karakter (U+00C0) indexét. Ez a karakter azonban kétféleképpen jeleníthető meg: egyetlen kódegységként (U+00C0) vagy összetett karakterként (két kódegység: U+0041 és U+0300). Ebben az esetben a karaktert a sztringpéldányban két Char objektum jelöli: U+0041 és U+0300. A példakód meghívja és String.IndexOf(Char)String.IndexOf(String) túlterheli a karakter pozícióját a sztringpéldányban, de ezek eltérő eredményeket adnak vissza. Az első metódushívás argumentumot Char ad meg, és a függvény sorszám-összehasonlítást végez, ezért nem talál egyezést. A második hívás argumentumokkal String rendelkezik; kulturális szempontból érzékeny összehasonlítást végez, ezért talál egyezést.
using System;
using System.Globalization;
using System.Threading;
public class Example17
{
public static void Main17()
{
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("pl-PL");
string composite = "\u0041\u0300";
Console.WriteLine("Comparing using Char: {0}", composite.IndexOf('\u00C0'));
Console.WriteLine("Comparing using String: {0}", composite.IndexOf("\u00C0"));
}
}
// The example displays the following output:
// Comparing using Char: -1
// Comparing using String: 0
Imports System.Globalization
Imports System.Threading
Module Example17
Public Sub Main17()
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("pl-PL")
Dim composite As String = ChrW(&H41) + ChrW(&H300)
Console.WriteLine("Comparing using Char: {0}", composite.IndexOf(ChrW(&HC0)))
Console.WriteLine("Comparing using String: {0}", composite.IndexOf(ChrW(&HC0).ToString()))
End Sub
End Module
' The example displays the following output:
' Comparing using Char: -1
' Comparing using String: 0
Elkerülheti a példa kétértelműségét (egy metódus két hasonló túlterhelését hívja meg, amelyek különböző eredményeket adnak vissza), ha egy StringComparison paramétert tartalmazó túlterhelést hív meg, például a String.IndexOf(String, StringComparison) metódust.String.LastIndexOf(String, StringComparison)
A keresések azonban nem mindig érzékenyek a kultúrára. Ha a keresés célja egy biztonsági döntés meghozatala, vagy egy erőforráshoz való hozzáférés engedélyezése vagy letiltása, az összehasonlításnak a következő szakaszban ismertetett módon kell lennie.
Egyenlőségi sztringek tesztelése
Ha az egyenlőség szempontjából két sztringet szeretne tesztelni ahelyett, hogy a rendezési sorrendben szeretné meghatározni az összehasonlítás módját, használja a String.Equals metódust a sztringek összehasonlítási módszere helyett, például String.Compare vagy CompareInfo.Compare.
Az egyenlőség összehasonlítását általában bizonyos erőforrások feltételes eléréséhez hajtják végre. Előfordulhat például, hogy összehasonlítja az egyenlőséget egy jelszó ellenőrzéséhez vagy egy fájl meglétének megerősítéséhez. Az ilyen nem nyelvi összehasonlításoknak mindig inkább az ordinálisnak kell lenniük, mint a kultúraérzékenyeknek. A példánymetódust String.Equals(String, StringComparison) vagy a statikus String.Equals(String, String, StringComparison) metódust általában sztringek, például jelszavak, sztringek, például fájlnevek vagy URI-k értékével StringComparison.OrdinalStringComparison.OrdinalIgnoreCase kell meghívni.
Az egyenlőségi összehasonlítások néha kereséseket vagy összevonásos összehasonlításokat is magukban foglalnak, nem pedig a metódushoz intézett String.Equals hívásokat. Bizonyos esetekben alsztringkereséssel megállapíthatja, hogy az alsztring egy másik sztringgel egyenlő-e. Ha az összehasonlítás célja nem nyelvi jellegű, akkor a keresésnek a kultúra szempontjából érzékeny helyett inkább a hagyományosnak kell lennie.
Az alábbi példa a nem nyelvi adatok kultúraérzékeny keresésének veszélyét szemlélteti. A AccessesFileSystem
metódus célja, hogy megtiltsa a fájlrendszerek hozzáférését a "FILE" alsztringgel kezdődő URI-k számára. Ehhez végrehajtja az URI elejének kultúraérzékeny, kis- és nagybetűs összehasonlítását a "FILE" sztringgel. Mivel a fájlrendszerhez hozzáférő URI a "FILE:" vagy a "file:" kezdetű lehet, az implicit feltételezés az, hogy az "i" (U+0069) mindig az "I" (U+0049) kisbetűs megfelelője. A török és az azerbajdzsáni nyelvben azonban az "i" nagybetűs verziója "İ" (U+0130). Az eltérés miatt a kultúraérzékeny összehasonlítás lehetővé teszi a fájlrendszer elérését, amikor azt tiltani kell.
using System;
using System.Globalization;
using System.Threading;
public class Example10
{
public static void Main10()
{
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("tr-TR");
string uri = @"file:\\c:\users\username\Documents\bio.txt";
if (!AccessesFileSystem(uri))
// Permit access to resource specified by URI
Console.WriteLine("Access is allowed.");
else
// Prohibit access.
Console.WriteLine("Access is not allowed.");
}
private static bool AccessesFileSystem(string uri)
{
return uri.StartsWith("FILE", true, CultureInfo.CurrentCulture);
}
}
// The example displays the following output:
// Access is allowed.
Imports System.Globalization
Imports System.Threading
Module Example10
Public Sub Main10()
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("tr-TR")
Dim uri As String = "file:\\c:\users\username\Documents\bio.txt"
If Not AccessesFileSystem(uri) Then
' Permit access to resource specified by URI
Console.WriteLine("Access is allowed.")
Else
' Prohibit access.
Console.WriteLine("Access is not allowed.")
End If
End Sub
Private Function AccessesFileSystem(uri As String) As Boolean
Return uri.StartsWith("FILE", True, CultureInfo.CurrentCulture)
End Function
End Module
' The example displays the following output:
' Access is allowed.
Ezt a problémát elkerülheti, ha olyan sorszám-összehasonlítást végez, amely figyelmen kívül hagyja az esetet, ahogy az az alábbi példában is látható.
using System;
using System.Globalization;
using System.Threading;
public class Example11
{
public static void Main11()
{
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("tr-TR");
string uri = @"file:\\c:\users\username\Documents\bio.txt";
if (!AccessesFileSystem(uri))
// Permit access to resource specified by URI
Console.WriteLine("Access is allowed.");
else
// Prohibit access.
Console.WriteLine("Access is not allowed.");
}
private static bool AccessesFileSystem(string uri)
{
return uri.StartsWith("FILE", StringComparison.OrdinalIgnoreCase);
}
}
// The example displays the following output:
// Access is not allowed.
Imports System.Globalization
Imports System.Threading
Module Example11
Public Sub Main11()
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("tr-TR")
Dim uri As String = "file:\\c:\users\username\Documents\bio.txt"
If Not AccessesFileSystem(uri) Then
' Permit access to resource specified by URI
Console.WriteLine("Access is allowed.")
Else
' Prohibit access.
Console.WriteLine("Access is not allowed.")
End If
End Sub
Private Function AccessesFileSystem(uri As String) As Boolean
Return uri.StartsWith("FILE", StringComparison.OrdinalIgnoreCase)
End Function
End Module
' The example displays the following output:
' Access is not allowed.
Sztringek rendezése és rendezése
A felhasználói felületen megjelenítendő rendezett sztringeket általában a kultúra alapján kell rendezni. Az ilyen sztring-összehasonlításokat általában implicit módon kezeli a .NET, amikor sztringeket (például Array.Sort vagy List<T>.Sort. Alapértelmezés szerint a sztringek az aktuális kultúra rendezési konvenciói alapján vannak rendezve. Az alábbi példa az angol (Egyesült Államok) kultúra és a svéd (Svédország) kultúra konvenciói alapján rendezi a sztringek tömbjeinek különbségét.
using System;
using System.Globalization;
using System.Threading;
public class Example18
{
public static void Main18()
{
string[] values = { "able", "ångström", "apple", "Æble",
"Windows", "Visual Studio" };
// Change thread to en-US.
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("en-US");
// Sort the array and copy it to a new array to preserve the order.
Array.Sort(values);
string[] enValues = (String[])values.Clone();
// Change culture to Swedish (Sweden).
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("sv-SE");
Array.Sort(values);
string[] svValues = (String[])values.Clone();
// Compare the sorted arrays.
Console.WriteLine("{0,-8} {1,-15} {2,-15}\n", "Position", "en-US", "sv-SE");
for (int ctr = 0; ctr <= values.GetUpperBound(0); ctr++)
Console.WriteLine("{0,-8} {1,-15} {2,-15}", ctr, enValues[ctr], svValues[ctr]);
}
}
// The example displays the following output:
// Position en-US sv-SE
//
// 0 able able
// 1 Æble Æble
// 2 ångström apple
// 3 apple Windows
// 4 Visual Studio Visual Studio
// 5 Windows ångström
Imports System.Globalization
Imports System.Threading
Module Example18
Public Sub Main18()
Dim values() As String = {"able", "ångström", "apple",
"Æble", "Windows", "Visual Studio"}
' Change thread to en-US.
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("en-US")
' Sort the array and copy it to a new array to preserve the order.
Array.Sort(values)
Dim enValues() As String = CType(values.Clone(), String())
' Change culture to Swedish (Sweden).
Thread.CurrentThread.CurrentCulture = New CultureInfo("sv-SE")
Array.Sort(values)
Dim svValues() As String = CType(values.Clone(), String())
' Compare the sorted arrays.
Console.WriteLine("{0,-8} {1,-15} {2,-15}", "Position", "en-US", "sv-SE")
Console.WriteLine()
For ctr As Integer = 0 To values.GetUpperBound(0)
Console.WriteLine("{0,-8} {1,-15} {2,-15}", ctr, enValues(ctr), svValues(ctr))
Next
End Sub
End Module
' The example displays the following output:
' Position en-US sv-SE
'
' 0 able able
' 1 Æble Æble
' 2 ångström apple
' 3 apple Windows
' 4 Visual Studio Visual Studio
' 5 Windows ångström
A kultúraérzékeny sztringek összehasonlítását az CompareInfo objektum határozza meg, amelyet az egyes kulturális környezetek tulajdonsága CultureInfo.CompareInfo ad vissza. A metódust túlterhelést használó String.Compare kultúraérzékeny sztring-összehasonlítások is használják az CompareInfo objektumot.
A .NET táblákat használ a sztringadatok kultúraérzékeny rendezésére. Ezeknek a táblázatoknak a tartalmát, amelyek a rendezési súlyokra és a sztring normalizálására vonatkozó adatokat tartalmazzák, a .NET egy adott verziója által implementált Unicode-szabvány verziója határozza meg. Az alábbi táblázat a .NET megadott verziói által implementált Unicode-verziókat sorolja fel. A támogatott Unicode-verziók listája csak a karakterek összehasonlítására és rendezésére vonatkozik; nem vonatkozik a Unicode-karakterek kategória szerinti besorolására. További információt a cikk "Sztringek és Unicode Standard" című szakaszában String talál.
.NET-keretrendszer verziója | Operációs rendszer | Unicode-verzió |
---|---|---|
.NET-keretrendszer 2.0 | Minden operációs rendszer | Unicode 4.1 |
.NET-keretrendszer 3.0 | Minden operációs rendszer | Unicode 4.1 |
.NET-keretrendszer 3.5 | Minden operációs rendszer | Unicode 4.1 |
.NET-keretrendszer 4 | Minden operációs rendszer | Unicode 5.0 |
.NET-keretrendszer 4.5-ös és újabb verziók | Windows 7 | Unicode 5.0 |
.NET-keretrendszer 4.5-ös és újabb verziók | Windows 8 és újabb operációs rendszerek | Unicode 6.3.0 |
.NET Core és .NET 5+ | Az alapul szolgáló operációs rendszer által támogatott Unicode Standard verziótól függ. |
A .NET-keretrendszer 4.5-től kezdve a .NET Core és a .NET 5+ összes verziójától kezdve a sztringek összehasonlítása és rendezése az operációs rendszertől függ. A Windows 7-en futó .NET-keretrendszer 4.5-ös és újabb verziói adatokat kérnek le a Unicode 5.0-t implementáló saját tábláiból. .NET-keretrendszer 4.5-ös és újabb verziók Windows 8-on és újabb verziókban a Unicode 6.3-at implementáló operációsrendszer-táblákból kér le adatokat. A .NET Core és a .NET 5+ rendszeren a Unicode támogatott verziója az alapul szolgáló operációs rendszertől függ. Ha kultúraérzékeny rendezési adatokat szerializál, az SortVersion osztály segítségével meghatározhatja, hogy mikor kell rendezni a szerializált adatokat, hogy azok összhangban legyenek a .NET-tel és az operációs rendszer rendezési sorrendjével. Példaként tekintse meg az osztály témakörét SortVersion .
Ha az alkalmazás széles körű kultúraspecifikus sztringadatokat végez, az osztálysal együttműködve összehasonlíthatja a SortKey sztringeket. A rendezési kulcsok a kultúraspecifikus rendezési súlyokat tükrözik, beleértve egy adott sztring betűrendes, kis- és melléksúlyát. Mivel a rendezési kulcsokat használó összehasonlítások binárisak, gyorsabbak, mint azok CompareInfo az összehasonlítások, amelyek implicit módon vagy explicit módon használnak objektumot. Egy adott sztring kultúraspecifikus rendezési kulcsát úgy hozhatja létre, hogy átadja a sztringet a CompareInfo.GetSortKey metódusnak.
Az alábbi példa az előző példához hasonló. Azonban a Array.Sort(Array) metódus meghívása helyett, amely implicit módon meghívja a CompareInfo.Compare metódust, egy olyan implementációt System.Collections.Generic.IComparer<T> határoz meg, amely összehasonlítja a rendezési kulcsokat, amelyeket létrehoz és átad a Array.Sort<T>(T[], IComparer<T>) metódusnak.
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Threading;
public class SortKeyComparer : IComparer<String>
{
public int Compare(string? str1, string? str2)
{
return (str1, str2) switch
{
(null, null) => 0,
(null, _) => -1,
(_, null) => 1,
(var s1, var s2) => SortKey.Compare(
CultureInfo.CurrentCulture.CompareInfo.GetSortKey(s1),
CultureInfo.CurrentCulture.CompareInfo.GetSortKey(s1))
};
}
}
public class Example19
{
public static void Main19()
{
string[] values = { "able", "ångström", "apple", "Æble",
"Windows", "Visual Studio" };
SortKeyComparer comparer = new SortKeyComparer();
// Change thread to en-US.
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("en-US");
// Sort the array and copy it to a new array to preserve the order.
Array.Sort(values, comparer);
string[] enValues = (String[])values.Clone();
// Change culture to Swedish (Sweden).
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("sv-SE");
Array.Sort(values, comparer);
string[] svValues = (String[])values.Clone();
// Compare the sorted arrays.
Console.WriteLine("{0,-8} {1,-15} {2,-15}\n", "Position", "en-US", "sv-SE");
for (int ctr = 0; ctr <= values.GetUpperBound(0); ctr++)
Console.WriteLine("{0,-8} {1,-15} {2,-15}", ctr, enValues[ctr], svValues[ctr]);
}
}
// The example displays the following output:
// Position en-US sv-SE
//
// 0 able able
// 1 Æble Æble
// 2 ångström apple
// 3 apple Windows
// 4 Visual Studio Visual Studio
// 5 Windows ångström
Imports System.Collections.Generic
Imports System.Globalization
Imports System.Threading
Public Class SortKeyComparer : Implements IComparer(Of String)
Public Function Compare(str1 As String, str2 As String) As Integer _
Implements IComparer(Of String).Compare
Dim sk1, sk2 As SortKey
sk1 = CultureInfo.CurrentCulture.CompareInfo.GetSortKey(str1)
sk2 = CultureInfo.CurrentCulture.CompareInfo.GetSortKey(str2)
Return SortKey.Compare(sk1, sk2)
End Function
End Class
Module Example19
Public Sub Main19()
Dim values() As String = {"able", "ångström", "apple",
"Æble", "Windows", "Visual Studio"}
Dim comparer As New SortKeyComparer()
' Change thread to en-US.
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("en-US")
' Sort the array and copy it to a new array to preserve the order.
Array.Sort(values, comparer)
Dim enValues() As String = CType(values.Clone(), String())
' Change culture to Swedish (Sweden).
Thread.CurrentThread.CurrentCulture = New CultureInfo("sv-SE")
Array.Sort(values, comparer)
Dim svValues() As String = CType(values.Clone(), String())
' Compare the sorted arrays.
Console.WriteLine("{0,-8} {1,-15} {2,-15}", "Position", "en-US", "sv-SE")
Console.WriteLine()
For ctr As Integer = 0 To values.GetUpperBound(0)
Console.WriteLine("{0,-8} {1,-15} {2,-15}", ctr, enValues(ctr), svValues(ctr))
Next
End Sub
End Module
' The example displays the following output:
' Position en-US sv-SE
'
' 0 able able
' 1 Æble Æble
' 2 ångström apple
' 3 apple Windows
' 4 Visual Studio Visual Studio
' 5 Windows ångström
Sztringösszefűzés elkerülése
Ha egyáltalán lehetséges, kerülje az összefűzött kifejezésekből futtatáskor létrehozott összetett sztringek használatát. Az összetett sztringeket nehéz honosítani, mert gyakran nyelvtani sorrendet feltételeznek az alkalmazás eredeti nyelvén, amely nem vonatkozik más honosított nyelvekre.
Dátumok és időpontok kezelése
A dátum- és időértékek kezelése attól függ, hogy megjelennek-e a felhasználói felületen, vagy megmaradnak. Ez a szakasz mindkét használatot megvizsgálja. Azt is ismerteti, hogyan kezelheti az időzóna-különbségeket és az aritmetikai műveleteket a dátumok és időpontok használatakor.
Dátumok és időpontok megjelenítése
Amikor a dátumok és időpontok megjelennek a felhasználói felületen, általában a felhasználói kultúra formázási konvencióit kell használnia, amelyeket a CultureInfo.CurrentCulture tulajdonság és a DateTimeFormatInfo tulajdonság által CultureInfo.CurrentCulture.DateTimeFormat
visszaadott objektum határoz meg. A rendszer automatikusan az aktuális kultúra formázási konvencióit használja a dátumok formázásához az alábbi módszerek bármelyikével:
A paraméter nélküli DateTime.ToString() metódus
A DateTime.ToString(String) formátumsztringet tartalmazó metódus
A paraméter nélküli DateTimeOffset.ToString() metódus
A DateTimeOffset.ToString(String)formátumsztringet tartalmazó
Az összetett formázási funkció, ha dátumokkal együtt használják
Az alábbi példa kétszer jeleníti meg a napkelte és a naplemente adatait 2012. október 11-én. Először horvát (Horvátország), majd angol (Egyesült Királyság) nyelvre állítja a jelenlegi kultúrát. A dátumok és időpontok minden esetben az adott kultúrának megfelelő formátumban jelennek meg.
using System;
using System.Globalization;
using System.Threading;
public class Example3
{
static DateTime[] dates = { new DateTime(2012, 10, 11, 7, 06, 0),
new DateTime(2012, 10, 11, 18, 19, 0) };
public static void Main3()
{
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("hr-HR");
ShowDayInfo();
Console.WriteLine();
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("en-GB");
ShowDayInfo();
}
private static void ShowDayInfo()
{
Console.WriteLine("Date: {0:D}", dates[0]);
Console.WriteLine(" Sunrise: {0:T}", dates[0]);
Console.WriteLine(" Sunset: {0:T}", dates[1]);
}
}
// The example displays the following output:
// Date: 11. listopada 2012.
// Sunrise: 7:06:00
// Sunset: 18:19:00
//
// Date: 11 October 2012
// Sunrise: 07:06:00
// Sunset: 18:19:00
Imports System.Globalization
Imports System.Threading
Module Example3
Dim dates() As Date = {New Date(2012, 10, 11, 7, 6, 0),
New Date(2012, 10, 11, 18, 19, 0)}
Public Sub Main3()
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("hr-HR")
ShowDayInfo()
Console.WriteLine()
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("en-GB")
ShowDayInfo()
End Sub
Private Sub ShowDayInfo()
Console.WriteLine("Date: {0:D}", dates(0))
Console.WriteLine(" Sunrise: {0:T}", dates(0))
Console.WriteLine(" Sunset: {0:T}", dates(1))
End Sub
End Module
' The example displays the following output:
' Date: 11. listopada 2012.
' Sunrise: 7:06:00
' Sunset: 18:19:00
'
' Date: 11 October 2012
' Sunrise: 07:06:00
' Sunset: 18:19:00
Dátumok és időpontok megőrzése
Soha ne őrizze meg a dátum- és időadatokat kulturális környezettől függően eltérő formátumban. Ez egy gyakori programozási hiba, amely sérült adatokat vagy futásidejű kivételt eredményez. Az alábbi példa két dátumot szerializál: 2013. január 9. és 2013. augusztus 18. sztringként az angol (Egyesült Államok) kultúra formázási konvencióit használva. Ha az adatok lekérése és elemzése az angol (Egyesült Államok) kultúra konvencióinak használatával történik, a rendszer sikeresen visszaállítja azokat. Ha azonban az angol (Egyesült Királyság) kultúra konvencióinak használatával kérik le és elemzik, az első dátumot helytelenül szeptember 1-ként értelmezik, a második pedig nem elemez, mert a Gergely-naptárnak nincs tizennyolcadik hónapja.
using System;
using System.IO;
using System.Globalization;
using System.Threading;
public class Example4
{
public static void Main4()
{
// Persist two dates as strings.
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("en-US");
DateTime[] dates = { new DateTime(2013, 1, 9),
new DateTime(2013, 8, 18) };
StreamWriter sw = new StreamWriter("dateData.dat");
sw.Write("{0:d}|{1:d}", dates[0], dates[1]);
sw.Close();
// Read the persisted data.
StreamReader sr = new StreamReader("dateData.dat");
string dateData = sr.ReadToEnd();
sr.Close();
string[] dateStrings = dateData.Split('|');
// Restore and display the data using the conventions of the en-US culture.
Console.WriteLine("Current Culture: {0}",
Thread.CurrentThread.CurrentCulture.DisplayName);
foreach (var dateStr in dateStrings)
{
DateTime restoredDate;
if (DateTime.TryParse(dateStr, out restoredDate))
Console.WriteLine("The date is {0:D}", restoredDate);
else
Console.WriteLine("ERROR: Unable to parse {0}", dateStr);
}
Console.WriteLine();
// Restore and display the data using the conventions of the en-GB culture.
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("en-GB");
Console.WriteLine("Current Culture: {0}",
Thread.CurrentThread.CurrentCulture.DisplayName);
foreach (var dateStr in dateStrings)
{
DateTime restoredDate;
if (DateTime.TryParse(dateStr, out restoredDate))
Console.WriteLine("The date is {0:D}", restoredDate);
else
Console.WriteLine("ERROR: Unable to parse {0}", dateStr);
}
}
}
// The example displays the following output:
// Current Culture: English (United States)
// The date is Wednesday, January 09, 2013
// The date is Sunday, August 18, 2013
//
// Current Culture: English (United Kingdom)
// The date is 01 September 2013
// ERROR: Unable to parse 8/18/2013
Imports System.Globalization
Imports System.IO
Imports System.Threading
Module Example4
Public Sub Main4()
' Persist two dates as strings.
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("en-US")
Dim dates() As DateTime = {New DateTime(2013, 1, 9),
New DateTime(2013, 8, 18)}
Dim sw As New StreamWriter("dateData.dat")
sw.Write("{0:d}|{1:d}", dates(0), dates(1))
sw.Close()
' Read the persisted data.
Dim sr As New StreamReader("dateData.dat")
Dim dateData As String = sr.ReadToEnd()
sr.Close()
Dim dateStrings() As String = dateData.Split("|"c)
' Restore and display the data using the conventions of the en-US culture.
Console.WriteLine("Current Culture: {0}",
Thread.CurrentThread.CurrentCulture.DisplayName)
For Each dateStr In dateStrings
Dim restoredDate As Date
If Date.TryParse(dateStr, restoredDate) Then
Console.WriteLine("The date is {0:D}", restoredDate)
Else
Console.WriteLine("ERROR: Unable to parse {0}", dateStr)
End If
Next
Console.WriteLine()
' Restore and display the data using the conventions of the en-GB culture.
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("en-GB")
Console.WriteLine("Current Culture: {0}",
Thread.CurrentThread.CurrentCulture.DisplayName)
For Each dateStr In dateStrings
Dim restoredDate As Date
If Date.TryParse(dateStr, restoredDate) Then
Console.WriteLine("The date is {0:D}", restoredDate)
Else
Console.WriteLine("ERROR: Unable to parse {0}", dateStr)
End If
Next
End Sub
End Module
' The example displays the following output:
' Current Culture: English (United States)
' The date is Wednesday, January 09, 2013
' The date is Sunday, August 18, 2013
'
' Current Culture: English (United Kingdom)
' The date is 01 September 2013
' ERROR: Unable to parse 8/18/2013
Ezt a problémát háromféleképpen kerülheti el:
- Sztring helyett bináris formátumban szerializálja a dátumot és az időt.
- A dátum és idő sztringképének mentése és elemzése a felhasználó kulturális környezetétől függetlenül azonos egyéni formátumsztring használatával.
- Mentse a sztringet az invariáns kultúra formázási konvencióinak használatával.
Az alábbi példa az utolsó megközelítést szemlélteti. A statikus CultureInfo.InvariantCulture tulajdonság által visszaadott invariáns kultúra formázási konvencióit használja.
using System;
using System.IO;
using System.Globalization;
using System.Threading;
public class Example5
{
public static void Main5()
{
// Persist two dates as strings.
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("en-US");
DateTime[] dates = { new DateTime(2013, 1, 9),
new DateTime(2013, 8, 18) };
StreamWriter sw = new StreamWriter("dateData.dat");
sw.Write(String.Format(CultureInfo.InvariantCulture,
"{0:d}|{1:d}", dates[0], dates[1]));
sw.Close();
// Read the persisted data.
StreamReader sr = new StreamReader("dateData.dat");
string dateData = sr.ReadToEnd();
sr.Close();
string[] dateStrings = dateData.Split('|');
// Restore and display the data using the conventions of the en-US culture.
Console.WriteLine("Current Culture: {0}",
Thread.CurrentThread.CurrentCulture.DisplayName);
foreach (var dateStr in dateStrings)
{
DateTime restoredDate;
if (DateTime.TryParse(dateStr, CultureInfo.InvariantCulture,
DateTimeStyles.None, out restoredDate))
Console.WriteLine("The date is {0:D}", restoredDate);
else
Console.WriteLine("ERROR: Unable to parse {0}", dateStr);
}
Console.WriteLine();
// Restore and display the data using the conventions of the en-GB culture.
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("en-GB");
Console.WriteLine("Current Culture: {0}",
Thread.CurrentThread.CurrentCulture.DisplayName);
foreach (var dateStr in dateStrings)
{
DateTime restoredDate;
if (DateTime.TryParse(dateStr, CultureInfo.InvariantCulture,
DateTimeStyles.None, out restoredDate))
Console.WriteLine("The date is {0:D}", restoredDate);
else
Console.WriteLine("ERROR: Unable to parse {0}", dateStr);
}
}
}
// The example displays the following output:
// Current Culture: English (United States)
// The date is Wednesday, January 09, 2013
// The date is Sunday, August 18, 2013
//
// Current Culture: English (United Kingdom)
// The date is 09 January 2013
// The date is 18 August 2013
Imports System.Globalization
Imports System.IO
Imports System.Threading
Module Example5
Public Sub Main5()
' Persist two dates as strings.
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("en-US")
Dim dates() As DateTime = {New DateTime(2013, 1, 9),
New DateTime(2013, 8, 18)}
Dim sw As New StreamWriter("dateData.dat")
sw.Write(String.Format(CultureInfo.InvariantCulture,
"{0:d}|{1:d}", dates(0), dates(1)))
sw.Close()
' Read the persisted data.
Dim sr As New StreamReader("dateData.dat")
Dim dateData As String = sr.ReadToEnd()
sr.Close()
Dim dateStrings() As String = dateData.Split("|"c)
' Restore and display the data using the conventions of the en-US culture.
Console.WriteLine("Current Culture: {0}",
Thread.CurrentThread.CurrentCulture.DisplayName)
For Each dateStr In dateStrings
Dim restoredDate As Date
If Date.TryParse(dateStr, CultureInfo.InvariantCulture,
DateTimeStyles.None, restoredDate) Then
Console.WriteLine("The date is {0:D}", restoredDate)
Else
Console.WriteLine("ERROR: Unable to parse {0}", dateStr)
End If
Next
Console.WriteLine()
' Restore and display the data using the conventions of the en-GB culture.
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("en-GB")
Console.WriteLine("Current Culture: {0}",
Thread.CurrentThread.CurrentCulture.DisplayName)
For Each dateStr In dateStrings
Dim restoredDate As Date
If Date.TryParse(dateStr, CultureInfo.InvariantCulture,
DateTimeStyles.None, restoredDate) Then
Console.WriteLine("The date is {0:D}", restoredDate)
Else
Console.WriteLine("ERROR: Unable to parse {0}", dateStr)
End If
Next
End Sub
End Module
' The example displays the following output:
' Current Culture: English (United States)
' The date is Wednesday, January 09, 2013
' The date is Sunday, August 18, 2013
'
' Current Culture: English (United Kingdom)
' The date is 09 January 2013
' The date is 18 August 2013
Szerializálás és időzóna-tudatosság
A dátum- és időértékek több értelmezést is tartalmazhatnak, az általános időponttól ("Az üzletek 2013. január 2-án 9:00-kor nyílnak meg") egy adott időpontig ("Születési dátum: 2013. január 2., 6:32:00"). Ha egy időérték egy adott időpontot jelöl, és szerializált értékből állítja vissza, akkor győződjön meg arról, hogy a felhasználó földrajzi helyétől vagy időzónájától függetlenül ugyanazt a pillanatot jelöli.
Az alábbi példa ezt a problémát szemlélteti. Egyetlen helyi dátum- és időértéket ment sztringként három szabványos formátumban:
- "G" az általános dátum hosszú ideje.
- "s" a rendezhető dátum/idő esetében.
- "o" az oda-vissza utazás dátumához/idejéhez.
using System;
using System.IO;
public class Example6
{
public static void Main6()
{
DateTime dateOriginal = new DateTime(2023, 3, 30, 18, 0, 0);
dateOriginal = DateTime.SpecifyKind(dateOriginal, DateTimeKind.Local);
// Serialize a date.
if (!File.Exists("DateInfo.dat"))
{
StreamWriter sw = new StreamWriter("DateInfo.dat");
sw.Write("{0:G}|{0:s}|{0:o}", dateOriginal);
sw.Close();
Console.WriteLine("Serialized dates to DateInfo.dat");
}
Console.WriteLine();
// Restore the date from string values.
StreamReader sr = new StreamReader("DateInfo.dat");
string datesToSplit = sr.ReadToEnd();
string[] dateStrings = datesToSplit.Split('|');
foreach (var dateStr in dateStrings)
{
DateTime newDate = DateTime.Parse(dateStr);
Console.WriteLine("'{0}' --> {1} {2}",
dateStr, newDate, newDate.Kind);
}
}
}
Imports System.IO
Module Example6
Public Sub Main6()
' Serialize a date.
Dim dateOriginal As Date = #03/30/2023 6:00PM#
dateOriginal = DateTime.SpecifyKind(dateOriginal, DateTimeKind.Local)
' Serialize the date in string form.
If Not File.Exists("DateInfo.dat") Then
Dim sw As New StreamWriter("DateInfo.dat")
sw.Write("{0:G}|{0:s}|{0:o}", dateOriginal)
sw.Close()
End If
' Restore the date from string values.
Dim sr As New StreamReader("DateInfo.dat")
Dim datesToSplit As String = sr.ReadToEnd()
Dim dateStrings() As String = datesToSplit.Split("|"c)
For Each dateStr In dateStrings
Dim newDate As DateTime = DateTime.Parse(dateStr)
Console.WriteLine("'{0}' --> {1} {2}",
dateStr, newDate, newDate.Kind)
Next
End Sub
End Module
Amikor az adatok a szerializálási rendszerrel azonos időzónában lévő rendszeren vannak visszaállítva, a deszerializált dátum- és időértékek pontosan tükrözik az eredeti értéket, ahogy a kimenet is mutatja:
'3/30/2013 6:00:00 PM' --> 3/30/2013 6:00:00 PM Unspecified
'2013-03-30T18:00:00' --> 3/30/2013 6:00:00 PM Unspecified
'2013-03-30T18:00:00.0000000-07:00' --> 3/30/2013 6:00:00 PM Local
Ha azonban egy másik időzónában lévő rendszeren állítja vissza az adatokat, csak az "o" (oda-vissza) standard formátumú sztringdel formázott dátum- és időérték őrzi meg az időzóna adatait, és ezért ugyanazt az időpontot jelöli. A következő kimenet jelenik meg, amikor a dátum- és időadatok visszaállnak egy rendszerben a Romantika standard időzónájában:
'3/30/2023 6:00:00 PM' --> 3/30/2023 6:00:00 PM Unspecified
'2023-03-30T18:00:00' --> 3/30/2023 6:00:00 PM Unspecified
'2023-03-30T18:00:00.0000000-07:00' --> 3/31/2023 3:00:00 AM Local
Az adatok deszerializálásának alapjául szolgáló rendszer időzónájától függetlenül egy dátum- és időérték pontos tükrözése érdekében az alábbi lehetőségek közül választhat:
- Mentse az értéket sztringként az "o" (oda-vissza) szabványos formátumsztring használatával. Ezután deszerializálja a célrendszeren.
- Alakítsa át UTC-re, és mentse sztringként az "r" (RFC1123) standard formátumú sztring használatával. Ezután deszerializálja a célrendszeren, és konvertálja helyi idő szerint.
- Alakítsa át UTC-vé, és mentse sztringként az "u" (univerzális rendezhető) standard formátumú sztring használatával. Ezután deszerializálja a célrendszeren, és konvertálja helyi idő szerint.
Az alábbi példa az egyes technikákat szemlélteti.
using System;
using System.IO;
public class Example9
{
public static void Main9()
{
// Serialize a date.
DateTime dateOriginal = new DateTime(2023, 3, 30, 18, 0, 0);
dateOriginal = DateTime.SpecifyKind(dateOriginal, DateTimeKind.Local);
// Serialize the date in string form.
if (!File.Exists("DateInfo2.dat"))
{
StreamWriter sw = new StreamWriter("DateInfo2.dat");
sw.Write("{0:o}|{1:r}|{1:u}", dateOriginal,
dateOriginal.ToUniversalTime());
sw.Close();
}
// Restore the date from string values.
StreamReader sr = new StreamReader("DateInfo2.dat");
string datesToSplit = sr.ReadToEnd();
string[] dateStrings = datesToSplit.Split('|');
for (int ctr = 0; ctr < dateStrings.Length; ctr++)
{
DateTime newDate = DateTime.Parse(dateStrings[ctr]);
if (ctr == 1)
{
Console.WriteLine($"'{dateStrings[ctr]}' --> {newDate} {newDate.Kind}");
}
else
{
DateTime newLocalDate = newDate.ToLocalTime();
Console.WriteLine($"'{dateStrings[ctr]}' --> {newLocalDate} {newLocalDate.Kind}");
}
}
}
}
Imports System.IO
Module Example9
Public Sub Main9()
' Serialize a date.
Dim dateOriginal As Date = #03/30/2023 6:00PM#
dateOriginal = DateTime.SpecifyKind(dateOriginal, DateTimeKind.Local)
' Serialize the date in string form.
If Not File.Exists("DateInfo2.dat") Then
Dim sw As New StreamWriter("DateInfo2.dat")
sw.Write("{0:o}|{1:r}|{1:u}", dateOriginal,
dateOriginal.ToUniversalTime())
sw.Close()
End If
' Restore the date from string values.
Dim sr As New StreamReader("DateInfo2.dat")
Dim datesToSplit As String = sr.ReadToEnd()
Dim dateStrings() As String = datesToSplit.Split("|"c)
For ctr As Integer = 0 To dateStrings.Length - 1
Dim newDate As DateTime = DateTime.Parse(dateStrings(ctr))
If ctr = 1 Then
Console.WriteLine("'{0}' --> {1} {2}",
dateStrings(ctr), newDate, newDate.Kind)
Else
Dim newLocalDate As DateTime = newDate.ToLocalTime()
Console.WriteLine("'{0}' --> {1} {2}",
dateStrings(ctr), newLocalDate, newLocalDate.Kind)
End If
Next
End Sub
End Module
Ha az adatok szerializálva vannak a Csendes-óceáni standard időzóna egy rendszerén, és deszerializálva vannak a Romantikus standard időzóna egy rendszerén, a példa a következő kimenetet jeleníti meg:
'2023-03-30T18:00:00.0000000-07:00' --> 3/31/2023 3:00:00 AM Local
'Sun, 31 Mar 2023 01:00:00 GMT' --> 3/31/2023 3:00:00 AM Local
'2023-03-31 01:00:00Z' --> 3/31/2023 3:00:00 AM Local
További információ: Időzónák közötti időszámítás.
Dátum- és időritkítás végrehajtása
Mind a típus, mind a DateTimeDateTimeOffset típus támogatja az aritmetikai műveleteket. Kiszámíthatja a két dátumérték közötti különbséget, vagy hozzáadhat vagy kivonhat bizonyos időintervallumokat egy dátumértékhez vagy abból. A dátum- és időértékek számtani műveletei azonban nem veszik figyelembe az időzónákat és az időzóna-kiigazítási szabályokat. Emiatt a pillanatokat ábrázoló értékek dátum- és időritmetikai eredményei pontatlan eredményeket adhatnak vissza.
A csendes-óceáni téli időről a csendes-óceáni nyári időre való áttérés például március második vasárnapján történik, amely 2013. március 10. Ahogy az alábbi példa is mutatja, ha a 2013. március 9-ét követő 48 órás dátumot és időt a Csendes-óceáni téli időzóna egy rendszerén 10:30-kor számítja ki, akkor a 2013. március 11-én 10:30-kor kapott eredmény nem veszi figyelembe a beavatkozó idő módosítását.
using System;
public class Example7
{
public static void Main7()
{
DateTime date1 = DateTime.SpecifyKind(new DateTime(2013, 3, 9, 10, 30, 0),
DateTimeKind.Local);
TimeSpan interval = new TimeSpan(48, 0, 0);
DateTime date2 = date1 + interval;
Console.WriteLine("{0:g} + {1:N1} hours = {2:g}",
date1, interval.TotalHours, date2);
}
}
// The example displays the following output:
// 3/9/2013 10:30 AM + 48.0 hours = 3/11/2013 10:30 AM
Module Example7
Public Sub Main7()
Dim date1 As Date = DateTime.SpecifyKind(#3/9/2013 10:30AM#,
DateTimeKind.Local)
Dim interval As New TimeSpan(48, 0, 0)
Dim date2 As Date = date1 + interval
Console.WriteLine("{0:g} + {1:N1} hours = {2:g}",
date1, interval.TotalHours, date2)
End Sub
End Module
' The example displays the following output:
' 3/9/2013 10:30 AM + 48.0 hours = 3/11/2013 10:30 AM
Annak érdekében, hogy a dátum- és időértékek számtani művelete pontos eredményeket adjon, kövesse az alábbi lépéseket:
- Konvertálja a forrás időzónában lévő időt UTC-vé.
- Hajtsa végre az aritmetikai műveletet.
- Ha az eredmény dátum- és időérték, konvertálja utc-ről a forrás időzónában lévő időpontra.
Az alábbi példa hasonló az előző példához, azzal a kivételrel, hogy az alábbi három lépéssel helyesen adhat hozzá 48 órát 2013. március 9-én 10:30-kor.
using System;
public class Example8
{
public static void Main8()
{
TimeZoneInfo pst = TimeZoneInfo.FindSystemTimeZoneById("Pacific Standard Time");
DateTime date1 = DateTime.SpecifyKind(new DateTime(2013, 3, 9, 10, 30, 0),
DateTimeKind.Local);
DateTime utc1 = date1.ToUniversalTime();
TimeSpan interval = new TimeSpan(48, 0, 0);
DateTime utc2 = utc1 + interval;
DateTime date2 = TimeZoneInfo.ConvertTimeFromUtc(utc2, pst);
Console.WriteLine("{0:g} + {1:N1} hours = {2:g}",
date1, interval.TotalHours, date2);
}
}
// The example displays the following output:
// 3/9/2013 10:30 AM + 48.0 hours = 3/11/2013 11:30 AM
Module Example8
Public Sub Main8()
Dim pst As TimeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Pacific Standard Time")
Dim date1 As Date = DateTime.SpecifyKind(#3/9/2013 10:30AM#,
DateTimeKind.Local)
Dim utc1 As Date = date1.ToUniversalTime()
Dim interval As New TimeSpan(48, 0, 0)
Dim utc2 As Date = utc1 + interval
Dim date2 As Date = TimeZoneInfo.ConvertTimeFromUtc(utc2, pst)
Console.WriteLine("{0:g} + {1:N1} hours = {2:g}",
date1, interval.TotalHours, date2)
End Sub
End Module
' The example displays the following output:
' 3/9/2013 10:30 AM + 48.0 hours = 3/11/2013 11:30 AM
További információ: Számtani műveletek végrehajtása dátumokkal és időpontokkal.
Kultúraérzékeny nevek használata dátumelemekhez
Előfordulhat, hogy az alkalmazásnak meg kell jelenítenie a hónap nevét vagy a hét napját. Ehhez gyakori az alábbihoz hasonló kód.
using System;
public class Example12
{
public static void Main12()
{
DateTime midYear = new DateTime(2013, 7, 1);
Console.WriteLine("{0:d} is a {1}.", midYear, GetDayName(midYear));
}
private static string GetDayName(DateTime date)
{
return date.DayOfWeek.ToString("G");
}
}
// The example displays the following output:
// 7/1/2013 is a Monday.
Module Example12
Public Sub Main12()
Dim midYear As Date = #07/01/2013#
Console.WriteLine("{0:d} is a {1}.", midYear, GetDayName(midYear))
End Sub
Private Function GetDayName(dat As Date) As String
Return dat.DayOfWeek.ToString("G")
End Function
End Module
' The example displays the following output:
' 7/1/2013 is a Monday.
Ez a kód azonban mindig a hét napjainak nevét adja vissza angolul. A hónap nevét kinyerő kód gyakran még rugalmatlanabb. Gyakran feltételezi, hogy egy tizenkét hónapos naptár egy adott nyelven hónapok nevével.
Az egyéni dátum- és időformátum-sztringek vagy az DateTimeFormatInfo objektum tulajdonságainak használatával könnyen kinyerhetők olyan sztringek, amelyek a felhasználó kulturális környezetében a hét vagy hónap napjainak nevét tükrözik, ahogyan az alábbi példa is mutatja. A jelenlegi kultúrát francia (Franciaország) értékre módosítja, és megjeleníti a hét napjának nevét és a hónap nevét 2013. július 1-jei dátumra.
using System;
using System.Globalization;
public class Example13
{
public static void Main13()
{
// Set the current culture to French (France).
CultureInfo.CurrentCulture = CultureInfo.CreateSpecificCulture("fr-FR");
DateTime midYear = new DateTime(2013, 7, 1);
Console.WriteLine("{0:d} is a {1}.", midYear, DateUtilities.GetDayName(midYear));
Console.WriteLine("{0:d} is a {1}.", midYear, DateUtilities.GetDayName((int)midYear.DayOfWeek));
Console.WriteLine("{0:d} is in {1}.", midYear, DateUtilities.GetMonthName(midYear));
Console.WriteLine("{0:d} is in {1}.", midYear, DateUtilities.GetMonthName(midYear.Month));
}
}
public static class DateUtilities
{
public static string GetDayName(int dayOfWeek)
{
if (dayOfWeek < 0 | dayOfWeek > DateTimeFormatInfo.CurrentInfo.DayNames.Length)
return String.Empty;
else
return DateTimeFormatInfo.CurrentInfo.DayNames[dayOfWeek];
}
public static string GetDayName(DateTime date)
{
return date.ToString("dddd");
}
public static string GetMonthName(int month)
{
if (month < 1 | month > DateTimeFormatInfo.CurrentInfo.MonthNames.Length - 1)
return String.Empty;
else
return DateTimeFormatInfo.CurrentInfo.MonthNames[month - 1];
}
public static string GetMonthName(DateTime date)
{
return date.ToString("MMMM");
}
}
// The example displays the following output:
// 01/07/2013 is a lundi.
// 01/07/2013 is a lundi.
// 01/07/2013 is in juillet.
// 01/07/2013 is in juillet.
Imports System.Globalization
Imports System.Threading
Module Example13
Public Sub Main13()
' Set the current culture to French (France).
CultureInfo.CurrentCulture = CultureInfo.CreateSpecificCulture("fr-FR")
Dim midYear As Date = #07/01/2013#
Console.WriteLine("{0:d} is a {1}.", midYear, DateUtilities.GetDayName(midYear))
Console.WriteLine("{0:d} is a {1}.", midYear, DateUtilities.GetDayName(midYear.DayOfWeek))
Console.WriteLine("{0:d} is in {1}.", midYear, DateUtilities.GetMonthName(midYear))
Console.WriteLine("{0:d} is in {1}.", midYear, DateUtilities.GetMonthName(midYear.Month))
End Sub
End Module
Public Class DateUtilities
Public Shared Function GetDayName(dayOfWeek As Integer) As String
If dayOfWeek < 0 Or dayOfWeek > DateTimeFormatInfo.CurrentInfo.DayNames.Length Then
Return String.Empty
Else
Return DateTimeFormatInfo.CurrentInfo.DayNames(dayOfWeek)
End If
End Function
Public Shared Function GetDayName(dat As Date) As String
Return dat.ToString("dddd")
End Function
Public Shared Function GetMonthName(month As Integer) As String
If month < 1 Or month > DateTimeFormatInfo.CurrentInfo.MonthNames.Length - 1 Then
Return String.Empty
Else
Return DateTimeFormatInfo.CurrentInfo.MonthNames(month - 1)
End If
End Function
Public Shared Function GetMonthName(dat As Date) As String
Return dat.ToString("MMMM")
End Function
End Class
' The example displays the following output:
' 01/07/2013 is a lundi.
' 01/07/2013 is a lundi.
' 01/07/2013 is in juillet.
' 01/07/2013 is in juillet.
Numerikus értékek
A számok kezelése attól függ, hogy megjelennek-e a felhasználói felületen, vagy megmaradnak. Ez a szakasz mindkét használatot megvizsgálja.
Feljegyzés
Az elemzési és formázási műveletekben a .NET csak a 0–9(U+0030–U+0039) egyszerű latin karaktereket ismeri fel numerikus számjegyként.
Numerikus értékek megjelenítése
Amikor számok jelennek meg a felhasználói felületen, általában a felhasználói kultúra formázási konvencióit kell használnia, amelyeket a CultureInfo.CurrentCulture tulajdonság és a NumberFormatInfo tulajdonság által CultureInfo.CurrentCulture.NumberFormat
visszaadott objektum határoz meg. Az aktuális kultúra formázási konvencióit a rendszer automatikusan használja, ha a következő módokon formáz egy dátumot:
- Bármely numerikus típus paraméter nélküli
ToString
metódusának használata. ToString(String)
Bármilyen numerikus típus metódusának használata, amely argumentumként egy formátumsztringet is tartalmaz.- Összetett formázás használata numerikus értékekkel.
Az alábbi példában a franciaországi Párizs havi átlaghőmérséklete látható. Először a francia (Franciaország) nyelvre állítja az aktuális kultúrát, mielőtt megjelenítené az adatokat, majd angolra (Egyesült Államok) állítja be. A hónapnevek és a hőmérsékletek minden esetben az adott kultúrának megfelelő formátumban jelennek meg. Vegye figyelembe, hogy a két kultúra különböző tizedeselválasztókat használ a hőmérsékleti értékben. Azt is vegye figyelembe, hogy a példa az "MMMM" egyéni dátum- és időformátum-sztringet használja a teljes hónapnév megjelenítéséhez, és a tömb leghosszabb hónapnevének hosszának meghatározásával lefoglalja a hónap nevének megfelelő mennyiségű helyet az DateTimeFormatInfo.MonthNames eredménysztringben.
using System;
using System.Globalization;
using System.Threading;
public class Example14
{
public static void Main14()
{
DateTime dateForMonth = new DateTime(2013, 1, 1);
double[] temperatures = { 3.4, 3.5, 7.6, 10.4, 14.5, 17.2,
19.9, 18.2, 15.9, 11.3, 6.9, 5.3 };
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("fr-FR");
Console.WriteLine("Current Culture: {0}", CultureInfo.CurrentCulture.DisplayName);
// Build the format string dynamically so we allocate enough space for the month name.
string fmtString = "{0,-" + GetLongestMonthNameLength().ToString() + ":MMMM} {1,4}";
for (int ctr = 0; ctr < temperatures.Length; ctr++)
Console.WriteLine(fmtString,
dateForMonth.AddMonths(ctr),
temperatures[ctr]);
Console.WriteLine();
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("en-US");
Console.WriteLine("Current Culture: {0}", CultureInfo.CurrentCulture.DisplayName);
fmtString = "{0,-" + GetLongestMonthNameLength().ToString() + ":MMMM} {1,4}";
for (int ctr = 0; ctr < temperatures.Length; ctr++)
Console.WriteLine(fmtString,
dateForMonth.AddMonths(ctr),
temperatures[ctr]);
}
private static int GetLongestMonthNameLength()
{
int length = 0;
foreach (var nameOfMonth in DateTimeFormatInfo.CurrentInfo.MonthNames)
if (nameOfMonth.Length > length) length = nameOfMonth.Length;
return length;
}
}
// The example displays the following output:
// Current Culture: French (France)
// janvier 3,4
// février 3,5
// mars 7,6
// avril 10,4
// mai 14,5
// juin 17,2
// juillet 19,9
// août 18,2
// septembre 15,9
// octobre 11,3
// novembre 6,9
// décembre 5,3
//
// Current Culture: English (United States)
// January 3.4
// February 3.5
// March 7.6
// April 10.4
// May 14.5
// June 17.2
// July 19.9
// August 18.2
// September 15.9
// October 11.3
// November 6.9
// December 5.3
Imports System.Globalization
Imports System.Threading
Module Example14
Public Sub Main14()
Dim dateForMonth As Date = #1/1/2013#
Dim temperatures() As Double = {3.4, 3.5, 7.6, 10.4, 14.5, 17.2,
19.9, 18.2, 15.9, 11.3, 6.9, 5.3}
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("fr-FR")
Console.WriteLine("Current Culture: {0}", CultureInfo.CurrentCulture.DisplayName)
Dim fmtString As String = "{0,-" + GetLongestMonthNameLength().ToString() + ":MMMM} {1,4}"
For ctr = 0 To temperatures.Length - 1
Console.WriteLine(fmtString,
dateForMonth.AddMonths(ctr),
temperatures(ctr))
Next
Console.WriteLine()
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("en-US")
Console.WriteLine("Current Culture: {0}", CultureInfo.CurrentCulture.DisplayName)
' Build the format string dynamically so we allocate enough space for the month name.
fmtString = "{0,-" + GetLongestMonthNameLength().ToString() + ":MMMM} {1,4}"
For ctr = 0 To temperatures.Length - 1
Console.WriteLine(fmtString,
dateForMonth.AddMonths(ctr),
temperatures(ctr))
Next
End Sub
Private Function GetLongestMonthNameLength() As Integer
Dim length As Integer
For Each nameOfMonth In DateTimeFormatInfo.CurrentInfo.MonthNames
If nameOfMonth.Length > length Then length = nameOfMonth.Length
Next
Return length
End Function
End Module
' The example displays the following output:
' Current Culture: French (France)
' janvier 3,4
' février 3,5
' mars 7,6
' avril 10,4
' mai 14,5
' juin 17,2
' juillet 19,9
' août 18,2
' septembre 15,9
' octobre 11,3
' novembre 6,9
' décembre 5,3
'
' Current Culture: English (United States)
' January 3.4
' February 3.5
' March 7.6
' April 10.4
' May 14.5
' June 17.2
' July 19.9
' August 18.2
' September 15.9
' October 11.3
' November 6.9
' December 5.3
Numerikus értékek megőrzése
A numerikus adatokat soha ne őrizze meg kultúraspecifikus formátumban. Ez egy gyakori programozási hiba, amely sérült adatokat vagy futásidejű kivételt eredményez. Az alábbi példa tíz véletlenszerű lebegőpontos számot hoz létre, majd sztringként szerializálja őket az angol (Egyesült Államok) kultúra formázási konvencióinak használatával. Ha az adatok lekérése és elemzése az angol (Egyesült Államok) kultúra konvencióinak használatával történik, a rendszer sikeresen visszaállítja azokat. Ha azonban lekéri és elemzi a francia (Franciaország) kultúra konvenciói alapján, a számok egyike sem elemezhető, mert a kultúrák különböző tizedeselválasztókat használnak.
using System;
using System.Globalization;
using System.IO;
using System.Threading;
public class Example15
{
public static void Main15()
{
// Create ten random doubles.
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("en-US");
double[] numbers = GetRandomNumbers(10);
DisplayRandomNumbers(numbers);
// Persist the numbers as strings.
StreamWriter sw = new StreamWriter("randoms.dat");
for (int ctr = 0; ctr < numbers.Length; ctr++)
sw.Write("{0:R}{1}", numbers[ctr], ctr < numbers.Length - 1 ? "|" : "");
sw.Close();
// Read the persisted data.
StreamReader sr = new StreamReader("randoms.dat");
string numericData = sr.ReadToEnd();
sr.Close();
string[] numberStrings = numericData.Split('|');
// Restore and display the data using the conventions of the en-US culture.
Console.WriteLine("Current Culture: {0}",
Thread.CurrentThread.CurrentCulture.DisplayName);
foreach (var numberStr in numberStrings)
{
double restoredNumber;
if (Double.TryParse(numberStr, out restoredNumber))
Console.WriteLine(restoredNumber.ToString("R"));
else
Console.WriteLine("ERROR: Unable to parse '{0}'", numberStr);
}
Console.WriteLine();
// Restore and display the data using the conventions of the fr-FR culture.
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("fr-FR");
Console.WriteLine("Current Culture: {0}",
Thread.CurrentThread.CurrentCulture.DisplayName);
foreach (var numberStr in numberStrings)
{
double restoredNumber;
if (Double.TryParse(numberStr, out restoredNumber))
Console.WriteLine(restoredNumber.ToString("R"));
else
Console.WriteLine("ERROR: Unable to parse '{0}'", numberStr);
}
}
private static double[] GetRandomNumbers(int n)
{
Random rnd = new Random();
double[] numbers = new double[n];
for (int ctr = 0; ctr < n; ctr++)
numbers[ctr] = rnd.NextDouble() * 1000;
return numbers;
}
private static void DisplayRandomNumbers(double[] numbers)
{
for (int ctr = 0; ctr < numbers.Length; ctr++)
Console.WriteLine(numbers[ctr].ToString("R"));
Console.WriteLine();
}
}
// The example displays output like the following:
// 487.0313743534644
// 674.12000879371533
// 498.72077885024288
// 42.3034229512808
// 970.57311049223563
// 531.33717716268131
// 587.82905693530529
// 562.25210175023039
// 600.7711019370571
// 299.46113717717174
//
// Current Culture: English (United States)
// 487.0313743534644
// 674.12000879371533
// 498.72077885024288
// 42.3034229512808
// 970.57311049223563
// 531.33717716268131
// 587.82905693530529
// 562.25210175023039
// 600.7711019370571
// 299.46113717717174
//
// Current Culture: French (France)
// ERROR: Unable to parse '487.0313743534644'
// ERROR: Unable to parse '674.12000879371533'
// ERROR: Unable to parse '498.72077885024288'
// ERROR: Unable to parse '42.3034229512808'
// ERROR: Unable to parse '970.57311049223563'
// ERROR: Unable to parse '531.33717716268131'
// ERROR: Unable to parse '587.82905693530529'
// ERROR: Unable to parse '562.25210175023039'
// ERROR: Unable to parse '600.7711019370571'
// ERROR: Unable to parse '299.46113717717174'
Imports System.Globalization
Imports System.IO
Imports System.Threading
Module Example15
Public Sub Main15()
' Create ten random doubles.
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("en-US")
Dim numbers() As Double = GetRandomNumbers(10)
DisplayRandomNumbers(numbers)
' Persist the numbers as strings.
Dim sw As New StreamWriter("randoms.dat")
For ctr As Integer = 0 To numbers.Length - 1
sw.Write("{0:R}{1}", numbers(ctr), If(ctr < numbers.Length - 1, "|", ""))
Next
sw.Close()
' Read the persisted data.
Dim sr As New StreamReader("randoms.dat")
Dim numericData As String = sr.ReadToEnd()
sr.Close()
Dim numberStrings() As String = numericData.Split("|"c)
' Restore and display the data using the conventions of the en-US culture.
Console.WriteLine("Current Culture: {0}",
Thread.CurrentThread.CurrentCulture.DisplayName)
For Each numberStr In numberStrings
Dim restoredNumber As Double
If Double.TryParse(numberStr, restoredNumber) Then
Console.WriteLine(restoredNumber.ToString("R"))
Else
Console.WriteLine("ERROR: Unable to parse '{0}'", numberStr)
End If
Next
Console.WriteLine()
' Restore and display the data using the conventions of the fr-FR culture.
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("fr-FR")
Console.WriteLine("Current Culture: {0}",
Thread.CurrentThread.CurrentCulture.DisplayName)
For Each numberStr In numberStrings
Dim restoredNumber As Double
If Double.TryParse(numberStr, restoredNumber) Then
Console.WriteLine(restoredNumber.ToString("R"))
Else
Console.WriteLine("ERROR: Unable to parse '{0}'", numberStr)
End If
Next
End Sub
Private Function GetRandomNumbers(n As Integer) As Double()
Dim rnd As New Random()
Dim numbers(n - 1) As Double
For ctr As Integer = 0 To n - 1
numbers(ctr) = rnd.NextDouble * 1000
Next
Return numbers
End Function
Private Sub DisplayRandomNumbers(numbers As Double())
For ctr As Integer = 0 To numbers.Length - 1
Console.WriteLine(numbers(ctr).ToString("R"))
Next
Console.WriteLine()
End Sub
End Module
' The example displays output like the following:
' 487.0313743534644
' 674.12000879371533
' 498.72077885024288
' 42.3034229512808
' 970.57311049223563
' 531.33717716268131
' 587.82905693530529
' 562.25210175023039
' 600.7711019370571
' 299.46113717717174
'
' Current Culture: English (United States)
' 487.0313743534644
' 674.12000879371533
' 498.72077885024288
' 42.3034229512808
' 970.57311049223563
' 531.33717716268131
' 587.82905693530529
' 562.25210175023039
' 600.7711019370571
' 299.46113717717174
'
' Current Culture: French (France)
' ERROR: Unable to parse '487.0313743534644'
' ERROR: Unable to parse '674.12000879371533'
' ERROR: Unable to parse '498.72077885024288'
' ERROR: Unable to parse '42.3034229512808'
' ERROR: Unable to parse '970.57311049223563'
' ERROR: Unable to parse '531.33717716268131'
' ERROR: Unable to parse '587.82905693530529'
' ERROR: Unable to parse '562.25210175023039'
' ERROR: Unable to parse '600.7711019370571'
' ERROR: Unable to parse '299.46113717717174'
A probléma elkerülése érdekében az alábbi technikák egyikét használhatja:
- Mentse és elemezje a szám sztring-ábrázolását egy egyéni formátumsztring használatával, amely a felhasználó kulturális környezetétől függetlenül megegyezik.
- Mentse a számot sztringként az invariáns kultúra formázási konvencióinak használatával, amelyet a tulajdonság visszaad CultureInfo.InvariantCulture .
A pénznemértékek szerializálása speciális eset. Mivel a pénznemérték attól függ, hogy a pénznem milyen mértékegységben van kifejezve, kevés értelme van független numerikus értékként kezelni. Ha azonban egy pénznemértéket olyan formázott sztringként ment, amely pénznemszimbólumot tartalmaz, az nem deszerializálható olyan rendszeren, amelynek alapértelmezett kultúrája eltérő pénznemszimbólumot használ, ahogyan az az alábbi példában látható.
using System;
using System.Globalization;
using System.IO;
using System.Threading;
public class Example1
{
public static void Main1()
{
// Display the currency value.
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("en-US");
Decimal value = 16039.47m;
Console.WriteLine("Current Culture: {0}", CultureInfo.CurrentCulture.DisplayName);
Console.WriteLine("Currency Value: {0:C2}", value);
// Persist the currency value as a string.
StreamWriter sw = new StreamWriter("currency.dat");
sw.Write(value.ToString("C2"));
sw.Close();
// Read the persisted data using the current culture.
StreamReader sr = new StreamReader("currency.dat");
string currencyData = sr.ReadToEnd();
sr.Close();
// Restore and display the data using the conventions of the current culture.
Decimal restoredValue;
if (Decimal.TryParse(currencyData, out restoredValue))
Console.WriteLine(restoredValue.ToString("C2"));
else
Console.WriteLine("ERROR: Unable to parse '{0}'", currencyData);
Console.WriteLine();
// Restore and display the data using the conventions of the en-GB culture.
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("en-GB");
Console.WriteLine("Current Culture: {0}",
Thread.CurrentThread.CurrentCulture.DisplayName);
if (Decimal.TryParse(currencyData, NumberStyles.Currency, null, out restoredValue))
Console.WriteLine(restoredValue.ToString("C2"));
else
Console.WriteLine("ERROR: Unable to parse '{0}'", currencyData);
Console.WriteLine();
}
}
// The example displays output like the following:
// Current Culture: English (United States)
// Currency Value: $16,039.47
// ERROR: Unable to parse '$16,039.47'
//
// Current Culture: English (United Kingdom)
// ERROR: Unable to parse '$16,039.47'
Imports System.Globalization
Imports System.IO
Imports System.Threading
Module Example1
Public Sub Main1()
' Display the currency value.
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("en-US")
Dim value As Decimal = 16039.47D
Console.WriteLine("Current Culture: {0}", CultureInfo.CurrentCulture.DisplayName)
Console.WriteLine("Currency Value: {0:C2}", value)
' Persist the currency value as a string.
Dim sw As New StreamWriter("currency.dat")
sw.Write(value.ToString("C2"))
sw.Close()
' Read the persisted data using the current culture.
Dim sr As New StreamReader("currency.dat")
Dim currencyData As String = sr.ReadToEnd()
sr.Close()
' Restore and display the data using the conventions of the current culture.
Dim restoredValue As Decimal
If Decimal.TryParse(currencyData, restoredValue) Then
Console.WriteLine(restoredValue.ToString("C2"))
Else
Console.WriteLine("ERROR: Unable to parse '{0}'", currencyData)
End If
Console.WriteLine()
' Restore and display the data using the conventions of the en-GB culture.
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("en-GB")
Console.WriteLine("Current Culture: {0}",
Thread.CurrentThread.CurrentCulture.DisplayName)
If Decimal.TryParse(currencyData, NumberStyles.Currency, Nothing, restoredValue) Then
Console.WriteLine(restoredValue.ToString("C2"))
Else
Console.WriteLine("ERROR: Unable to parse '{0}'", currencyData)
End If
Console.WriteLine()
End Sub
End Module
' The example displays output like the following:
' Current Culture: English (United States)
' Currency Value: $16,039.47
' ERROR: Unable to parse '$16,039.47'
'
' Current Culture: English (United Kingdom)
' ERROR: Unable to parse '$16,039.47'
Ehelyett szerializálnia kell a numerikus értéket néhány kulturális információval, például a kultúra nevével együtt, hogy az érték és a pénznem szimbóluma a jelenlegi kultúrától függetlenül deszerializálható legyen. A következő példa egy két tagú struktúrát határoz meg CurrencyValue
: az Decimal értéket és annak a kultúrának a nevét, amelyhez az érték tartozik.
using System;
using System.Globalization;
using System.Text.Json;
using System.Threading;
public class Example2
{
public static void Main2()
{
// Display the currency value.
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("en-US");
Decimal value = 16039.47m;
Console.WriteLine($"Current Culture: {CultureInfo.CurrentCulture.DisplayName}");
Console.WriteLine($"Currency Value: {value:C2}");
// Serialize the currency data.
CurrencyValue data = new()
{
Amount = value,
CultureName = CultureInfo.CurrentCulture.Name
};
string serialized = JsonSerializer.Serialize(data);
Console.WriteLine();
// Change the current culture.
CultureInfo.CurrentCulture = CultureInfo.CreateSpecificCulture("en-GB");
Console.WriteLine($"Current Culture: {CultureInfo.CurrentCulture.DisplayName}");
// Deserialize the data.
CurrencyValue restoredData = JsonSerializer.Deserialize<CurrencyValue>(serialized);
// Display the round-tripped value.
CultureInfo culture = CultureInfo.CreateSpecificCulture(restoredData.CultureName);
Console.WriteLine($"Currency Value: {restoredData.Amount.ToString("C2", culture)}");
}
}
internal struct CurrencyValue
{
public decimal Amount { get; set; }
public string CultureName { get; set; }
}
// The example displays the following output:
// Current Culture: English (United States)
// Currency Value: $16,039.47
//
// Current Culture: English (United Kingdom)
// Currency Value: $16,039.47
Imports System.Globalization
Imports System.Text.Json
Imports System.Threading
Friend Structure CurrencyValue
Public Property Amount As Decimal
Public Property CultureName As String
End Structure
Module Example2
Public Sub Main2()
' Display the currency value.
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("en-US")
Dim value As Decimal = 16039.47D
Console.WriteLine("Current Culture: {0}", CultureInfo.CurrentCulture.DisplayName)
Console.WriteLine("Currency Value: {0:C2}", value)
' Serialize the currency data.
Dim data As New CurrencyValue With {
.Amount = value,
.CultureName = CultureInfo.CurrentCulture.Name
}
Dim serialized As String = JsonSerializer.Serialize(data)
Console.WriteLine()
' Change the current culture.
CultureInfo.CurrentCulture = CultureInfo.CreateSpecificCulture("en-GB")
Console.WriteLine("Current Culture: {0}", CultureInfo.CurrentCulture.DisplayName)
' Deserialize the data.
Dim restoredData As CurrencyValue = JsonSerializer.Deserialize(Of CurrencyValue)(serialized)
' Display the round-tripped value.
Dim culture As CultureInfo = CultureInfo.CreateSpecificCulture(restoredData.CultureName)
Console.WriteLine("Currency Value: {0}", restoredData.Amount.ToString("C2", culture))
End Sub
End Module
' The example displays the following output:
' Current Culture: English (United States)
' Currency Value: $16,039.47
'
' Current Culture: English (United Kingdom)
' Currency Value: $16,039.47
Kultúraspecifikus beállítások használata
A .NET-ben az CultureInfo osztály egy adott kultúrát vagy régiót jelöl. Néhány tulajdonsága olyan objektumokat ad vissza, amelyek konkrét információkat nyújtanak a kultúra bizonyos aspektusairól:
A CultureInfo.CompareInfo tulajdonság egy CompareInfo objektumot ad vissza, amely információkat tartalmaz a kultúra összehasonlításáról és a sztringek megrendeléséről.
A CultureInfo.DateTimeFormat tulajdonság egy DateTimeFormatInfo objektumot ad vissza, amely a dátum- és időadatok formázásához használt kultúraspecifikus információkat tartalmazza.
A CultureInfo.NumberFormat tulajdonság egy NumberFormatInfo objektumot ad vissza, amely a numerikus adatok formázásához használt kultúraspecifikus információkat nyújt.
A CultureInfo.TextInfo tulajdonság egy TextInfo objektumot ad vissza, amely információt nyújt a kultúra írási rendszeréről.
Általában ne feltételezz semmilyen feltételezést az adott CultureInfo tulajdonságok és azok kapcsolódó objektumainak értékeiről. Ehelyett a kultúraspecifikus adatokat a következő okokból érdemes módosítani:
Az egyes tulajdonságértékek időbeli módosítása és módosítása az adatok javítása, a jobb adatok elérhetővé válása vagy a kultúraspecifikus konvenciók változásának függvényében történik.
Az egyes tulajdonságértékek a .NET vagy az operációs rendszer verzióiban eltérőek lehetnek.
A .NET támogatja a cserekultúrák használatát. Ez lehetővé teszi egy új egyéni kultúra meghatározását, amely vagy kiegészíti a meglévő standard kultúrákat, vagy teljesen lecserél egy meglévő standard kultúrát.
Windows rendszereken a felhasználó testre szabhatja a kultúraspecifikus beállításokat a Régió és nyelv alkalmazással a Vezérlőpult. Amikor példányosít egy CultureInfo objektumot, a konstruktor meghívásával meghatározhatja, hogy azok tükrözik-e ezeket a CultureInfo(String, Boolean) felhasználói testreszabásokat. A végfelhasználói alkalmazások esetében általában tiszteletben kell tartani a felhasználói beállításokat, hogy a felhasználó az általuk várt formátumban jelenjen meg.