Globalleştirme

Genelleştirme, birden çok kültürdeki kullanıcılar için yerelleştirilmiş arabirimleri ve bölgesel verileri destekleyen, dünya çapında kullanıma hazır bir uygulama tasarlamayı ve geliştirmeyi içerir. Tasarım aşamasına başlamadan önce uygulamanızın hangi kültürleri destekleyeceğini belirlemeniz gerekir. Bir uygulama varsayılan olarak tek bir kültürü veya bölgeyi hedeflese de, diğer kültür veya bölgelerdeki kullanıcılara kolayca genişletilmesi için tasarlayabilir ve yazabilirsiniz.

Geliştiriciler olarak, kültürlerimiz tarafından oluşturulan kullanıcı arabirimleri ve veriler hakkında hepimizin varsayımları vardır. Örneğin, Birleşik Devletler İngilizce konuşan bir geliştirici için tarih ve saat verilerini biçiminde MM/dd/yyyy hh:mm:ss bir dize olarak seri hale getirme son derece makul görünüyor. Ancak, farklı bir kültürdeki bir sistemdeki dizenin seri durumdan çıkarılması büyük olasılıkla bir FormatException özel durum oluşturur veya yanlış veriler üretir. Genelleştirme, kültüre özgü varsayımları tanımlamamıza ve uygulamamızın tasarımını veya kodunu etkilemediğinden emin olmamıza olanak tanır.

Bu makalede, dikkate almanız gereken bazı önemli sorunlar ve genelleştirilmiş bir uygulamada dizeleri, tarih ve saat değerlerini ve sayısal değerleri işlerken izleyebileceğiniz en iyi yöntemler ele alınmaktadır.

Dizeler

Karakterlerin ve dizelerin işlenmesi genelleştirmenin merkezi bir odağıdır çünkü her kültür veya bölge farklı karakterler ve karakter kümeleri kullanabilir ve bunları farklı sıralayabilir. Bu bölüm, genelleştirilmiş uygulamalarda dizeleri kullanmaya yönelik öneriler sağlar.

Unicode'un dahili olarak kullanılması

.NET varsayılan olarak Unicode dizeleri kullanır. Unicode dizesi, her biri utf-16 kod birimini temsil eden sıfır, bir veya daha fazla Char nesneden oluşur. Dünya genelinde kullanılan her karakter kümesindeki hemen her karakter için bir Unicode gösterimi vardır.

Windows işletim sistemi de dahil olmak üzere birçok uygulama ve işletim sistemi, karakter kümelerini temsil etmek için kod sayfalarını da kullanabilir. Kod sayfaları genellikle 0x00 ile 0x7F arasında standart ASCII değerlerini içerir ve diğer karakterleri 0x80 ile 0xFF arasında kalan değerlerle eşler. 0x80 ile 0xFF arasında değerlerin yorumlanması, belirli kod sayfasına bağlıdır. Bu nedenle, mümkünse genelleştirilmiş bir uygulamada kod sayfalarını kullanmaktan kaçınmanız gerekir.

Aşağıdaki örnek, bir sistemdeki varsayılan kod sayfası verilerin kaydedildiği kod sayfasından farklı olduğunda kod sayfası verilerini yorumlamanın tehlikelerini gösterir. (Bu senaryonun benzetimini yapmak için örnek, farklı kod sayfalarını açıkça belirtir.) İlk olarak, örnek Yunan alfabesinin büyük harf karakterlerinden oluşan bir dizi tanımlar. 737 kod sayfasını (MS-DOS Yunanca olarak da bilinir) kullanarak bunları bir bayt dizisine kodlar ve bayt dizisini bir dosyaya kaydeder. Dosya alınırsa ve bayt dizisi kod sayfası 737 kullanılarak çözülmezse, özgün karakterler geri yüklenir. Ancak, dosya alınırsa ve bayt dizisi kod sayfası 1252 (veya Latin alfabesindeki karakterleri temsil eden Windows-1252) kullanılarak çözülmezse, özgün karakterler kaybolur.

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:
'       ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩ
'       €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’""•–—

Unicode kullanımı, aynı kod birimlerinin her zaman aynı karakterlerle eşlemesini ve aynı karakterlerin her zaman aynı bayt dizileriyle eşlemesini sağlar.

Kaynak dosyalarını kullanma

Tek bir kültürü veya bölgeyi hedefleyen bir uygulama geliştiriyor olsanız bile, kullanıcı arabiriminde görüntülenen dizeleri ve diğer kaynakları depolamak için kaynak dosyalarını kullanmanız gerekir. Bunları asla doğrudan kodunuza eklememelisiniz. Kaynak dosyalarını kullanmanın çeşitli avantajları vardır:

  • Tüm dizeler tek bir konumdadır. Belirli bir dil veya kültür için değiştirebileceğiniz dizeleri tanımlamak için kaynak kodunuz genelinde arama yapmak zorunda değilsiniz.
  • Dizeleri yinelemeye gerek yoktur. Kaynak dosyalarını kullanmayan geliştiriciler genellikle aynı dizeyi birden çok kaynak kodu dosyasında tanımlar. Bu yineleme, bir dize değiştirildiğinde bir veya daha fazla örneğin göz ardı edilme olasılığını artırır.
  • Görüntüleri veya ikili verileri gibi dize dışı kaynakları, kolayca alınabilmeleri için ayrı bir tek başına dosyada depolamak yerine kaynak dosyasına ekleyebilirsiniz.

Yerelleştirilmiş bir uygulama oluşturuyorsanız kaynak dosyalarını kullanmanın belirli avantajları vardır. Kaynakları uydu derlemelerinde dağıttığınızda, ortak dil çalışma zamanı özelliği tarafından CultureInfo.CurrentUICulture tanımlanan kullanıcının geçerli ui kültürüne göre otomatik olarak kültüre uygun bir kaynak seçer. Kültüre özgü uygun bir kaynak sağladığınız ve doğru bir ResourceManager nesne örneği oluşturduğunuz veya kesin olarak belirlenmiş bir kaynak sınıfı kullandığınız sürece, çalışma zamanı uygun kaynakları alma ayrıntılarını işler.

Kaynak dosyaları oluşturma hakkında daha fazla bilgi için bkz . Kaynak dosyaları oluşturma. Uydu derlemeleri oluşturma ve dağıtma hakkında bilgi için bkz . Uydu derlemeleri oluşturma ve Kaynakları paketleme ve dağıtma.

Dizeleri arama ve karşılaştırma

Mümkün olduğunda, dizeleri tek tek bir karakter dizisi olarak işlemek yerine dizelerin tamamını işlemeniz gerekir. Bu, özellikle birleştirilmiş karakterleri ayrıştırmayla ilişkili sorunları önlemek için alt dizeleri sıraladığınızda veya aradığınızda önemlidir.

İpucu

sınıfını StringInfo bir dizedeki tek tek karakterler yerine metin öğeleriyle çalışmak için kullanabilirsiniz.

Dize aramalarında ve karşılaştırmalarında, dizeyi her biri bir nesneyle temsil edilen bir karakter koleksiyonu olarak ele almak yaygın bir Char hatadır. Aslında, tek bir karakter bir, iki veya daha fazla Char nesne tarafından oluşturulabilir. Bu tür karakterler en sık, alfabeleri Unicode Temel Latin karakter aralığının (U+0021 ile U+007E) dışındaki karakterlerden oluşan kültürlerden dizelerde bulunur. Aşağıdaki örnek, bir dizede LATIN BÜYÜK HARF A WITH GRAVE karakterinin (U+00C0) dizinini bulmaya çalışır. Ancak bu karakter iki farklı şekilde gösterilebilir: tek bir kod birimi (U+00C0) veya bileşik karakter (iki kod birimi: U+0041 ve U+0300). Bu durumda, karakter dize örneğinde U+0041 ve U+0300 olarak iki Char nesneyle temsil edilir. Örnek kod, dize örneğinde bu karakterin konumunu bulmak için ve String.IndexOf(String) aşırı yüklemelerini çağırırString.IndexOf(Char), ancak bunlar farklı sonuçlar döndürür. İlk yöntem çağrısının bağımsız Char değişkeni vardır; sıralı bir karşılaştırma gerçekleştirir ve bu nedenle eşleşme bulamaz. İkinci çağrının bağımsız String değişkeni vardır; kültüre duyarlı bir karşılaştırma gerçekleştirir ve bu nedenle bir eşleşme bulur.

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

Veya String.LastIndexOf(String, StringComparison) yöntemi gibi bir StringComparison parametre içeren bir aşırı yüklemeyi çağırarak bu örneğin belirsizliğinden (farklı sonuçlar döndüren bir yöntemin iki benzer aşırı yüklemesine String.IndexOf(String, StringComparison) çağrılar) kaçınabilirsiniz.

Ancak, aramalar her zaman kültüre duyarlı değildir. Aramanın amacı bir güvenlik kararı vermek veya bazı kaynaklara erişim izni vermek veya erişime izin vermek değilse, karşılaştırmanın sonraki bölümde açıklandığı gibi sıralı olması gerekir.

Eşitlik için dizeleri test edin

İki dizeyi sıralama düzeninde nasıl karşılaştırdıklarını belirlemek yerine eşitlik için test etmek istiyorsanız, veya CompareInfo.Comparegibi String.Compare bir dize karşılaştırma yöntemi yerine yöntemini kullanınString.Equals.

Eşitlik karşılaştırmaları genellikle bazı kaynaklara koşullu olarak erişmek için gerçekleştirilir. Örneğin, bir parolayı doğrulamak veya bir dosyanın var olduğunu onaylamak için eşitlik karşılaştırması gerçekleştirebilirsiniz. Bu tür dilsel olmayan karşılaştırmalar her zaman kültüre duyarlı değil sıralı olmalıdır. Genel olarak, parolalar gibi dizeler için değerine StringComparison.Ordinal ve dosya adları veya URI'ler gibi dizeler için değerine StringComparison.OrdinalIgnoreCase sahip örnek String.Equals(String, StringComparison) yöntemini veya statik String.Equals(String, String, StringComparison) yöntemi çağırmanız gerekir.

Eşitlik karşılaştırmaları bazen yöntemine yapılan çağrılar String.Equals yerine aramalar veya alt dize karşılaştırmaları içerir. Bazı durumlarda, alt dizenin başka bir dizeye eşit olup olmadığını belirlemek için bir alt dize araması kullanabilirsiniz. Bu karşılaştırmanın amacı dilsel değilse, arama kültüre duyarlı değil sıralı olmalıdır.

Aşağıdaki örnek, dilsel olmayan verilerde kültüre duyarlı aramanın tehlikesini göstermektedir. yöntemi, AccessesFileSystem "FILE" alt dizesiyle başlayan URI'ler için dosya sistemi erişimini yasaklama amacıyla tasarlanmıştır. Bunu yapmak için, URI'nin başlangıcını "FILE" dizesiyle kültüre duyarlı, büyük/küçük harfe duyarlı olmayan bir karşılaştırma gerçekleştirir. Dosya sistemine erişen bir URI "FILE:" veya "file:" ile başlayabildiğinden, örtük varsayım "i" (U+0069) her zaman "I" (U+0049) küçük harf eşdeğeridir. Ancak Türkçe ve Azerbaycan dilinde "i"nin büyük harfli versiyonu "İ" (U+0130) şeklindedir. Bu tutarsızlık nedeniyle kültüre duyarlı karşılaştırma, yasaklanması gereken durumlarda dosya sistemi erişimine izin verir.

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.

Aşağıdaki örnekte gösterildiği gibi, büyük/küçük harf durumunu yoksayan bir sıralı karşılaştırma yaparak bu sorundan kaçınabilirsiniz.

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.

Dizeleri sıralama ve sıralama

Genellikle, kullanıcı arabiriminde görüntülenecek sıralı dizeler kültüre göre sıralanmalıdır. Çoğunlukla, veya gibi dizeleri sıralayan bir yöntem çağırdığınızda bu tür dize karşılaştırmaları .NET tarafından örtük olarak Array.SortList<T>.Sortişlenir. Varsayılan olarak, dizeler geçerli kültürün sıralama kuralları kullanılarak sıralanır. Aşağıdaki örnekte, bir dize dizisinin İngilizce (Birleşik Devletler) kültürü ve İsveççe (İsveç) kültürü kuralları kullanılarak sıralandığı fark gösterilmektedir.

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

Kültüre duyarlı dize karşılaştırması, her kültürün CompareInfoCultureInfo.CompareInfo özelliği tarafından döndürülen nesnesi tarafından tanımlanır. Yöntem aşırı yüklemelerini kullanan kültüre String.Compare duyarlı dize karşılaştırmaları da nesnesini kullanır CompareInfo .

.NET, dize verilerinde kültüre duyarlı sıralamalar gerçekleştirmek için tabloları kullanır. Sıralama ağırlıkları ve dize normalleştirme verileri içeren bu tabloların içeriği, belirli bir .NET sürümü tarafından uygulanan Unicode standardı sürümü tarafından belirlenir. Aşağıdaki tabloda, belirtilen .NET sürümleri tarafından uygulanan Unicode sürümleri listelenmektedir. Desteklenen Unicode sürümlerinin bu listesi yalnızca karakter karşılaştırma ve sıralama için geçerlidir; Unicode karakterlerinin kategoriye göre sınıflandırılması için geçerli değildir. Daha fazla bilgi için makalenin "Dizeler ve Unicode Standardı" bölümüne String bakın.

.NET Framework sürümü İşletim sistemi Unicode sürümü
.NET Framework 2.0 Tüm işletim sistemleri Unicode 4.1
.NET Framework 3.0 Tüm işletim sistemleri Unicode 4.1
.NET Framework 3.5 Tüm işletim sistemleri Unicode 4.1
.NET Framework 4 Tüm işletim sistemleri Unicode 5.0
.NET Framework 4.5 ve üzeri Windows 7 Unicode 5.0
.NET Framework 4.5 ve üzeri Windows 8 ve üzeri işletim sistemleri Unicode 6.3.0
.NET Core ve .NET 5+ Temel işletim sistemi tarafından desteklenen Unicode Standardı sürümüne bağlıdır.

.NET Framework 4.5 ile başlayarak ve .NET Core ve .NET 5+ sürümlerinin tüm sürümlerinde, dize karşılaştırma ve sıralama işletim sistemine bağlıdır. Windows 7 üzerinde çalışan .NET Framework 4.5 ve üzeri, Unicode 5.0 uygulayan kendi tablolarından veri alır. Windows 8 ve sonraki sürümlerde çalışan .NET Framework 4.5 ve üzeri, Unicode 6.3 uygulayan işletim sistemi tablolarından veri alır. .NET Core ve .NET 5+ sürümlerinde, Desteklenen Unicode sürümü temel işletim sistemine bağlıdır. Kültüre duyarlı sıralanmış verileri serileştirirseniz, .NET ve işletim sisteminin sıralama düzeniyle tutarlı olması için serileştirilmiş verilerinizin ne zaman sıralanması gerektiğini belirlemek için sınıfını kullanabilirsiniz SortVersion . Bir örnek için sınıf konusuna SortVersion bakın.

Uygulamanız kültüre özgü kapsamlı dize verisi türleri gerçekleştiriyorsa, dizeleri karşılaştırmak için sınıfıyla SortKey çalışabilirsiniz. Sıralama anahtarı, belirli bir dizenin alfabetik, büyük/küçük harf ve aksan ağırlıkları da dahil olmak üzere kültüre özgü sıralama ağırlıklarını yansıtır. Sıralama anahtarları kullanan karşılaştırmalar ikili olduğundan, örtük veya açıkça bir CompareInfo nesne kullanan karşılaştırmalardan daha hızlıdır. Dizeyi yöntemine geçirerek belirli bir dize için kültüre CompareInfo.GetSortKey özgü bir sıralama anahtarı oluşturursunuz.

Aşağıdaki örnek, önceki örneğe benzer. Ancak, örtük olarak yöntemini çağıran yöntemini çağırmak Array.Sort(Array)CompareInfo.Compare yerine, örnekleme yaptığı ve yöntemine Array.Sort<T>(T[], IComparer<T>) geçirdiği sıralama anahtarlarını karşılaştıran bir System.Collections.Generic.IComparer<T> uygulama tanımlar.

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

Dize birleştirmeyi önleme

Mümkünse, birleştirilmiş tümceciklerden çalışma zamanında oluşturulan bileşik dizeleri kullanmaktan kaçının. Bileşik dizelerin yerelleştirilmesi zordur çünkü genellikle uygulamanın özgün dilinde diğer yerelleştirilmiş dillere uygulanmayan bir dil bilgisi sırası varsayılır.

Tarihleri ve saatleri işleme

Tarih ve saat değerlerinin nasıl işleneceği, bunların kullanıcı arabiriminde görüntülenip görüntülenmediğine veya kalıcı olmasına bağlıdır. Bu bölüm her iki kullanımı da inceler. Ayrıca tarih ve saatlerle çalışırken saat dilimi farklarını ve aritmetik işlemleri nasıl işleyebileceğiniz de açıklanır.

Tarihleri ve saatleri görüntüleme

Genellikle, tarihler ve saatler kullanıcı arabiriminde görüntülendiğinde, özelliği ve özelliği tarafından CultureInfo.CurrentCulture.DateTimeFormat döndürülen nesnesi tarafından CultureInfo.CurrentCulture tanımlanan kullanıcı kültürünün DateTimeFormatInfo biçimlendirme kurallarını kullanmanız gerekir. Geçerli kültürün biçimlendirme kuralları, şu yöntemlerden herhangi birini kullanarak bir tarihi biçimlendirdiğinizde otomatik olarak kullanılır:

Aşağıdaki örnek, 11 Ekim 2012 için gün doğumu ve gün batımı verilerini iki kez görüntüler. İlk olarak mevcut kültürü Hırvatçe (Hırvatistan) ve ardından İngilizce (Birleşik Krallık) olarak ayarlar. Her durumda, tarihler ve saatler bu kültüre uygun biçimde görüntülenir.

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

Tarihleri ve saatleri kalıcı hale

Tarih ve saat verilerini hiçbir zaman kültüre göre değişiklik gösterebilecek bir biçimde kalıcı hale getirirsiniz. Bu, bozuk veri veya çalışma zamanı özel durumuyla sonuçlanan yaygın bir programlama hatasıdır. Aşağıdaki örnek, İngilizce (Birleşik Devletler) kültürünün biçimlendirme kurallarını kullanarak iki tarihi (9 Ocak 2013 ve 18 Ağustos 2013) dize olarak seri hale getirmektedir. veriler İngilizce (Birleşik Devletler) kültürü kuralları kullanılarak alınıp ayrıştırıldığında başarıyla geri yüklenir. Ancak, İngilizce (Birleşik Krallık) kültürünün kuralları kullanılarak alındığında ve ayrıştırıldığında, ilk tarih yanlış bir şekilde 1 Eylül olarak yorumlanır ve Gregoryen takvimin on sekizinci ayı olmadığından ikinci tarih ayrıştırılamaz.

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

Bu sorunu üç yoldan herhangi biriyle önleyebilirsiniz:

  • Tarih ve saati dize olarak değil ikili biçimde seri hale getirme.
  • Kullanıcının kültüründen bağımsız olarak aynı olan özel bir biçim dizesi kullanarak tarih ve saatin dize gösterimini kaydedin ve ayrıştırın.
  • Sabit kültürün biçimlendirme kurallarını kullanarak dizeyi kaydedin.

Aşağıdaki örnekte son yaklaşım gösterilmektedir. Statik CultureInfo.InvariantCulture özellik tarafından döndürülen sabit kültürün biçimlendirme kurallarını kullanır.

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

Serileştirme ve saat dilimi farkındalığı

Tarih ve saat değeri, genel bir saat ("2 Ocak 2013'te, 09:00'da açık olan mağazalar") belirli bir zamana ("Doğum tarihi: 2 Ocak 2013 6:32:00 M.") kadar birçok yoruma sahip olabilir. Bir saat değeri belirli bir zamanı temsil ettiğinde ve bunu serileştirilmiş bir değerden geri yüklerseniz, kullanıcının coğrafi konumuna veya saat dilimine bakılmaksızın aynı anı temsil ettiğinden emin olmalısınız.

Aşağıdaki örnekte bu sorun gösterilmektedir. Tek bir yerel tarih ve saat değerini üç standart biçimde dize olarak kaydeder:

  • Genel tarih uzun saati için "G".
  • Sıralanabilir tarih/saat için "s".
  • Gidiş dönüş tarihi/saati için "o".
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

Veriler seri hale getirildiği sistemle aynı saat dilimindeki bir sisteme geri yüklendiğinde seri durumdan çıkarılmış tarih ve saat değerleri çıktıda gösterildiği gibi özgün değeri doğru şekilde yansıtır:

'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

Ancak, verileri farklı bir saat dilimindeki bir sisteme geri yüklerseniz, yalnızca "o" (gidiş dönüş) standart biçim dizesiyle biçimlendirilmiş tarih ve saat değeri saat dilimi bilgilerini korur ve bu nedenle aynı anında zamanı temsil eder. Romance Standard Saat dilimindeki bir sistemde tarih ve saat verilerinin geri yükleneceği çıkış aşağıda açıklanmıştır:

'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

Verilerin seri durumdan çıkarıldığı sistemin saat diliminden bağımsız olarak tek bir saati temsil eden tarih ve saat değerini doğru bir şekilde yansıtmak için aşağıdakilerden herhangi birini yapabilirsiniz:

  • "o" (gidiş dönüş) standart biçim dizesini kullanarak değeri dize olarak kaydedin. Ardından hedef sistemde seri durumdan kaldırın.
  • BUNU UTC'ye dönüştürün ve "r" (RFC1123) standart biçim dizesini kullanarak dize olarak kaydedin. Ardından hedef sistemde seri durumdan çıkararak yerel saate dönüştürün.
  • Bunu UTC'ye dönüştürün ve "u" (evrensel sıralanabilir) standart biçim dizesini kullanarak dize olarak kaydedin. Ardından hedef sistemde seri durumdan çıkararak yerel saate dönüştürün.

Aşağıdaki örnekte her teknik gösterilmektedir.

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

Veriler Pasifik Standart Saat dilimindeki bir sistemde seri hale getirildiğinde ve Romance Standard Saat dilimindeki bir sistemde seri durumdan çıkarıldığında, örnek aşağıdaki çıkışı görüntüler:

'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

Daha fazla bilgi için bkz . Saatleri saat dilimleri arasında dönüştürme.

Tarih ve saat aritmetiği gerçekleştirme

DateTime Hem hem de DateTimeOffset türleri aritmetik işlemleri destekler. İki tarih değeri arasındaki farkı hesaplayabilir veya bir tarih değerine belirli zaman aralıklarını ekleyebilir veya çıkarabilirsiniz. Ancak tarih ve saat değerleri üzerindeki aritmetik işlemler saat dilimlerini ve saat dilimi ayarlama kurallarını hesaba katmaz. Bu nedenle, zaman içindeki anları temsil eden değerlerdeki tarih ve saat aritmetiği yanlış sonuçlar döndürebilir.

Örneğin, Pasifik Standart Saati'nden Pasifik Yaz Saati'ne geçiş, 2013 yılı için 10 Mart olan Mart ayının ikinci Pazar günü gerçekleşir. Aşağıdaki örnekte gösterildiği gibi, Pasifik Standart Saat dilimindeki bir sistemde 9 Mart 2013'te saat 10:30'da 48 saat olan tarih ve saati hesaplarsanız, 11 Mart 2013 saat 10:30'da elde edilen sonuç, araya giren zaman ayarlamasını dikkate almaz.

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

Tarih ve saat değerleri üzerindeki aritmetik bir işlemin doğru sonuçlara neden olduğundan emin olmak için şu adımları izleyin:

  1. Kaynak saat dilimindeki saati UTC'ye dönüştürün.
  2. Aritmetik işlemi gerçekleştirin.
  3. Sonuç bir tarih ve saat değeriyse, bunu UTC'den kaynak saat dilimindeki saate dönüştürün.

Aşağıdaki örnek önceki örneğe benzer, ancak 9 Mart 2013 saat 10:30'a doğru 48 saat eklemek için bu üç adımı izler.

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

Daha fazla bilgi için bkz . Tarih ve saatlerle aritmetik işlemler gerçekleştirme.

Tarih öğeleri için kültüre duyarlı adlar kullanma

Uygulamanızın ayın adını veya haftanın gününü görüntülemesi gerekebilir. Bunu yapmak için aşağıdaki gibi kodlar yaygın olarak bulunur.

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.

Ancak bu kod her zaman haftanın günlerinin adlarını İngilizce döndürür. Ayın adını ayıklayan kod genellikle daha esnek değildir. Genellikle belirli bir dilde ayların adlarını içeren on iki aylık bir takvim varsayılır.

Özel tarih ve saat biçim dizelerini veya nesnenin DateTimeFormatInfo özelliklerini kullanarak, aşağıdaki örnekte gösterildiği gibi kullanıcının kültüründe haftanın veya ayların adlarını yansıtan dizeleri ayıklamak kolaydır. Geçerli kültürü Fransızca (Fransa) olarak değiştirir ve haftanın gününün adını ve 1 Temmuz 2013 için ayın adını görüntüler.

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.

Sayısal değerler

Sayıların işlenmesi, bunların kullanıcı arabiriminde görüntülenip görüntülenmediğine veya kalıcı olmasına bağlıdır. Bu bölüm her iki kullanımı da inceler.

Not

.NET, ayrıştırma ve biçimlendirme işlemlerinde yalnızca 0 ile 9 (U+0030 - U+0039 arasında) Temel Latin karakterlerini sayısal basamak olarak tanır.

Sayısal değerleri görüntüleme

Genellikle, sayılar kullanıcı arabiriminde görüntülendiğinde, özelliği ve özelliği tarafından döndürülen nesnesi tarafından CultureInfo.CurrentCulture.NumberFormat tanımlanan kullanıcı kültürünün CultureInfo.CurrentCultureNumberFormatInfo biçimlendirme kurallarını kullanmanız gerekir. Geçerli kültürün biçimlendirme kuralları, bir tarihi aşağıdaki yollarla biçimlendirdiğinizde otomatik olarak kullanılır:

  • Herhangi bir sayısal türün parametresiz ToString yöntemini kullanma.
  • ToString(String) Bağımsız değişken olarak bir biçim dizesi içeren herhangi bir sayısal türün yöntemini kullanma.
  • Sayısal değerlerle bileşik biçimlendirme kullanma.

Aşağıdaki örnek, Paris, Fransa'da aylık ortalama sıcaklığı görüntüler. Verileri görüntülemeden önce geçerli kültürü Fransızca (Fransa) olarak ayarlar ve sonra da İngilizce (Birleşik Devletler) olarak ayarlar. Her durumda, ay adları ve sıcaklıkları bu kültüre uygun biçimde görüntülenir. İki kültürün sıcaklık değerinde farklı ondalık ayırıcılar kullandığını unutmayın. Ayrıca örnekte tam ay adını görüntülemek için "MMMM" özel tarih ve saat biçimi dizesinin kullanıldığına ve dizideki en uzun ay adının uzunluğunu belirleyerek sonuç dizesindeki ay adı için uygun miktarda alan ayrıldığına DateTimeFormatInfo.MonthNames dikkat edin.

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

Sayısal değerleri kalıcı hale

Sayısal verileri hiçbir zaman kültüre özgü bir biçimde kalıcı hale yerleştirmemelisiniz. Bu, bozuk veri veya çalışma zamanı özel durumuyla sonuçlanan yaygın bir programlama hatasıdır. Aşağıdaki örnek on rastgele kayan noktalı sayı oluşturur ve sonra İngilizce (Birleşik Devletler) kültürünün biçimlendirme kurallarını kullanarak bunları dize olarak serileştirir. veriler İngilizce (Birleşik Devletler) kültürü kuralları kullanılarak alınıp ayrıştırıldığında başarıyla geri yüklenir. Ancak, Fransızca (Fransa) kültürünün kuralları kullanılarak alınıp ayrıştırıldığında, kültürler farklı ondalık ayırıcılar kullandığından sayıların hiçbiri ayrıştırılamaz.

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'

Bu sorunu önlemek için şu tekniklerden birini kullanabilirsiniz:

  • Kullanıcının kültüründen bağımsız olarak aynı olan özel bir biçim dizesi kullanarak sayının dize gösterimini kaydedin ve ayrıştırın.
  • Özelliği tarafından CultureInfo.InvariantCulture döndürülen sabit kültürün biçimlendirme kurallarını kullanarak sayıyı dize olarak kaydedin.

Para birimi değerlerini seri hale getirme özel bir durumdur. Para birimi değeri, ifade edildiği para birimine bağlı olduğundan, bağımsız bir sayısal değer olarak ele almak çok az mantıklıdır. Ancak, bir para birimi değerini para birimi simgesi içeren biçimlendirilmiş bir dize olarak kaydederseniz, aşağıdaki örnekte gösterildiği gibi varsayılan kültürü farklı bir para birimi simgesi kullanan bir sistemde seri durumdan çıkarılamaz.

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'

Bunun yerine, değerin ve para birimi simgesinin geçerli kültürden bağımsız olarak seri durumdan çıkarılabilmesi için sayısal değeri kültürün adı gibi bazı kültürel bilgilerle birlikte seri hale getirmeniz gerekir. Aşağıdaki örnek bunu iki üyeyle bir CurrencyValue yapı tanımlayarak yapar: Decimal değeri ve değerin ait olduğu kültürün adı.

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

Kültüre özgü ayarlarla çalışma

.NET'te sınıfı belirli CultureInfo bir kültürü veya bölgeyi temsil eder. Bazı özellikleri, bir kültürün bazı yönleri hakkında belirli bilgiler sağlayan nesneler döndürür:

Genel olarak, belirli CultureInfo özelliklerin değerleri ve ilgili nesneleri hakkında herhangi bir varsayımda bulunmayın. Bunun yerine, kültüre özgü verileri şu nedenlerle değiştirilebilir olarak görüntülemeniz gerekir:

  • Veriler düzeltildikçe, daha iyi veriler kullanılabilir hale geldikçe veya kültüre özgü kurallar değiştikçe, tek tek özellik değerleri zaman içinde değiştirilebilir ve düzeltilebilir.

  • Tek tek özellik değerleri .NET veya işletim sistemi sürümleri arasında farklılık gösterebilir.

  • .NET, değiştirme kültürlerini destekler. Bu, mevcut standart kültürleri tamamlayan veya mevcut standart kültürü tamamen değiştiren yeni bir özel kültür tanımlamayı mümkün kılar.

  • Windows sistemlerinde kullanıcı, Denetim Masası'da Bölge ve Dil uygulamasını kullanarak kültüre özgü ayarları özelleştirebilir. Bir CultureInfo nesnenin örneğini oluştururken oluşturucuyu çağırarak CultureInfo(String, Boolean) bu kullanıcı özelleştirmelerini yansıtıp yansıtmadığını belirleyebilirsiniz. Genellikle, son kullanıcı uygulamalarında, kullanıcıya bekledikleri biçimde veri sunulması için kullanıcı tercihlerine dikkat etmelisiniz.

Ayrıca bkz.