GlobalizzazioneGlobalization

La globalizzazione comporta la progettazione e lo sviluppo di un'app internazionalizzata che supporti interfacce localizzate e dati locali per utenti in più impostazioni cultura.Globalization involves designing and developing a world-ready app that supports localized interfaces and regional data for users in multiple cultures. Prima di iniziare la fase di progettazione, è necessario determinare quali impostazioni cultura verranno supportate dall'app.Before beginning the design phase, you should determine which cultures your app will support. Sebbene un'app sia destinata per impostazione predefinita a singole impostazioni cultura o a una singola area, è possibile progettarla e scriverla in modo che possa essere facilmente estesa agli utenti di altre impostazioni cultura o aree.Although an app targets a single culture or region as its default, you can design and write it so that it can easily be extended to users in other cultures or regions.

Gli sviluppatori partono sempre da supposizione su interfacce utente e dati che sono relativi alle impostazioni cultura.As developers, we all have assumptions about user interfaces and data that are formed by our cultures. Ad esempio, per uno sviluppatore di lingua inglese negli Stati Uniti, la serializzazione di data e ora sotto forma di stringa nel formato MM/dd/yyyy hh:mm:ss sembra perfettamente ragionevole.For example, for an English-speaking developer in the United States, serializing date and time data as a string in the format MM/dd/yyyy hh:mm:ss seems perfectly reasonable. Tuttavia, la deserializzazione di questa stringa in un sistema con impostazioni cultura diverse potrebbe generare un'eccezione FormatException o dati non accurati.However, deserializing that string on a system in a different culture is likely to throw a FormatException exception or produce inaccurate data. La globalizzazione consente di identificare queste supposizioni relative alle impostazioni cultura e di garantire che non influiscano sulla progettazione o sul codice dell'app.Globalization enables us to identify such culture-specific assumptions and ensure that they do not affect our app's design or code.

Nelle sezioni seguenti vengono descritti alcuni dei principali aspetti da considerare e le procedure consigliate da seguire quando si gestiscono stringhe, valori di data e ora e valori numerici in un'app globalizzata.The following sections discuss some of the major issues you should consider and the best practices you can follow when handling strings, date and time values, and numeric values in a globalized app.

Gestione delle stringheHandling Strings

La gestione di caratteri e stringhe è un elemento cruciale nella globalizzazione, in quanto le impostazioni cultura o area possono usare caratteri e set di caratteri diversi e ordinarli in modo diverso.The handling of characters and strings is a central focus of globalization, because each culture or region may use different characters and character sets and sort them differently. Questa sezione include suggerimenti per l'uso delle stringhe nelle app globalizzate.This section provides recommendations for using strings in globalized apps.

Utilizzare Unicode internamenteUse Unicode Internally

Per impostazione predefinita, .NET Framework usa stringhe Unicode.By default, the .NET Framework uses Unicode strings. Una stringa Unicode è costituita da zero, da uno o più oggetti Char, ognuno dei quali rappresenta un'unità di codice UTF-16.A Unicode string consists of zero, one, or more Char objects, each of which represents a UTF-16 code unit. Esiste una rappresentazione in formato Unicode di quasi tutti i caratteri inclusi nei set di caratteri usati nel mondo.There is a Unicode representation for almost every character in every character set in use throughout the world.

In molti sistemi operativi e applicazioni, incluso il sistema operativo Windows, è possibile usare anche tabelle codici per rappresentare i set di caratteri.Many applications and operating systems, including the Windows operating system, can use also use code pages to represent character sets. Le tabelle codici in genere contengono i valori ASCII standard compresi tra 0x00 e 0x7F ed eseguono il mapping degli altri caratteri ai valori rimanenti compresi tra 0x80 e 0xFF.Code pages typically contain the standard ASCII values from 0x00 through 0x7F and map other characters to the remaining values from 0x80 through 0xFF. L'interpretazione dei valori da 0x80 a 0xFF dipende dalla tabella codici specifica.The interpretation of values from 0x80 through 0xFF depends on the specific code page. Per questo motivo, se possibile, è consigliabile evitare l'uso di tabelle codici in un'app globalizzata.Because of this, you should avoid using code pages in a globalized app if possible.

Nell'esempio seguente vengono illustrati i rischi di interpretazione dei dati della tabella codici quando la tabella codici predefinita in un sistema è diversa dalla tabella codici in cui i sono stati salvati i dati.The following example illustrates the dangers of interpreting code page data when the default code page on a system is different from the code page on which the data was saved. Per simulare questo scenario, l'esempio specifica in modo esplicito tabelle codici diverse. Innanzitutto, nell'esempio viene definita una matrice costituita dai caratteri maiuscoli dell'alfabeto greco.(To simulate this scenario, the example explicitly specifies different code pages.) First, the example defines an array that consists of the uppercase characters of the Greek alphabet. I caratteri vengono codificati in una matrice di byte usando la tabella codici 737 (nota anche come Greco MS-DOS) e la matrice di byte viene salvata in un file.It encodes them into a byte array by using code page 737 (also known as MS-DOS Greek) and saves the byte array to a file. Se viene recuperato il file e viene decodificata la relativa matrice di byte tramite la tabella codici 737, vengono ripristinati i caratteri originali.If the file is retrieved and its byte array is decoded by using code page 737, the original characters are restored. Tuttavia, se viene recuperato il file e viene decodificata la relativa matrice di byte usando la tabella codici 1252 (o Windows-1252, che rappresenta i caratteri nell'alfabeto latino), i caratteri originali vengono persi.However, if the file is retrieved and its byte array is decoded by using code page 1252 (or Windows-1252, which represents characters in the Latin alphabet), the original characters are lost.

using System;
using System.IO;
using System.Text;

public class Example
{
   public static void Main()
   {
      // Represent Greek uppercase characters in code page 737.
      char[] greekChars = { 'Α', 'Β', 'Γ', 'Δ', 'Ε', 'Ζ', 'Η', 'Θ', 
                            'Ι', 'Κ', 'Λ', 'Μ', 'Ν', 'Ξ', 'Ο', 'Π', 
                            'Ρ', 'Σ', 'Τ', 'Υ', 'Φ', 'Χ', 'Ψ', 'Ω' };
      
      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 Main()
      ' 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 }
      
      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:
'       ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩ
'       €‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’""•–—

L'uso di Unicode assicura che le stesse unità di codice eseguono sempre il mapping agli stessi caratteri e che gli stessi caratteri eseguono sempre il mapping alle stesse matrici di byte.The use of Unicode ensures that the same code units always map to the same characters, and that the same characters always map to the same byte arrays.

Utilizzare file di risorseUse Resource Files

Anche se si sviluppa un'app destinata a singole impostazioni cultura o aree, è necessario usare file di risorse per archiviare le stringhe e altre risorse visualizzate nell'interfaccia utente.Even if you are developing an app that targets a single culture or region, you should use resource files to store strings and other resources that are displayed in the user interface. Si raccomanda di non aggiungerli mai direttamente al codice.You should never add them directly to your code. L'uso di file di risorse presenta una serie di vantaggi:Using resource files has a number of advantages:

  • Tutte le stringhe si trovano in un'unica posizione.All the strings are in a single location. Non è necessario eseguire la ricerca in tutto il codice di origine per identificare le stringhe da modificare per una lingua o impostazioni cultura specifiche.You don't have to search throughout your source code to identify strings to modify for a specific language or culture.

  • Non è necessario duplicare le stringhe.There is no need to duplicate strings. Gli sviluppatori che non usano file di risorse spesso definiscono la stessa stringa in più file di codice sorgente.Developers who don't use resource files often define the same string in multiple source code files. Questa duplicazione aumenta la probabilità che una o più istanze possano essere ignorate quando viene modificata una stringa.This duplication increases the probability that one or more instances will be overlooked when a string is modified.

  • È possibile includere risorse non di tipo stringa, ad esempio immagini o dati binari, nel file di risorse anziché archiviarle in un file autonomo separato, per poterle recuperare facilmente.You can include non-string resources, such as images or binary data, in the resource file instead of storing them in a separate standalone file, so they can be retrieved easily.

L'uso di file di risorse presenta vantaggi specifici se si crea un'app localizzata.Using resource files has particular advantages if you are creating a localized app. Quando si distribuiscono le risorse in assembly satellite, Common Language Runtime seleziona automaticamente una risorsa di impostazioni cultura appropriata basata sulle impostazioni cultura dell'interfaccia utente corrente come specificato dalla proprietà CultureInfo.CurrentUICulture.When you deploy resources in satellite assemblies, the common language runtime automatically selects a culture-appropriate resource based on the user's current UI culture as defined by the CultureInfo.CurrentUICulture property. Purché venga definita una risorsa specifica delle impostazioni cultura adatta e si crei correttamente un'istanza di un oggetto ResourceManager o si usi una classe di risorse fortemente tipizzata, il runtime gestisce i dettagli relativi al recupero delle risorse appropriate.As long as you provide an appropriate culture-specific resource and correctly instantiate a ResourceManager object or use a strongly typed resource class, the runtime handles the details of retrieving the appropriate resources.

Per altre informazioni sulla creazione di file di risorse, vedere Creazione di file di risorse.For more information about creating resource files, see Creating Resource Files. Per informazioni sulla creazione e distribuzione di assembly satellite, vedere Creazione di assembly satellite e Creazione del pacchetto e distribuzione delle risorse.For information about creating and deploying satellite assemblies, see Creating Satellite Assemblies and Packaging and Deploying Resources.

Ricerca e confronto delle stringheSearching and Comparing Strings

Quando possibile, si raccomanda di gestire le stringhe come unità intere, anziché come serie di caratteri singoli.Whenever possible, you should handle strings as entire strings instead of handling them as a series of individual characters. Ciò è particolarmente importante quando si ordinano o cercano le sottostringhe, per impedire problemi associati all'analisi dei caratteri combinati.This is especially important when you sort or search for substrings, to prevent problems associated with parsing combined characters.

Suggerimento

È possibile usare la classe StringInfo per gestire gli elementi di testo anziché i singoli caratteri in una stringa.You can use the StringInfo class to work with the text elements rather than the individual characters in a string.

Nelle ricerche e nei confronti di stringhe, un errore comune consiste nel gestire la stringa come una raccolta di caratteri, ognuno dei quali è rappresentato da un oggetto Char.In string searches and comparisons, a common mistake is to treat the string as a collection of characters, each of which is represented by a Char object. Infatti, un singolo carattere può essere costituito da uno, due o più oggetti Char.In fact, a single character may be formed by one, two, or more Char objects. Caratteri di questo tipo vengono trovati più frequentemente nelle stringhe delle impostazioni cultura i cui alfabeti sono costituiti da caratteri esterni all'intervallo di caratteri latini di base Unicode (da U+0021 a U+007E).Such characters are found most frequently in strings from cultures whose alphabets consist of characters outside the Unicode Basic Latin character range (U+0021 through U+007E). Nell'esempio seguente si tenta di trovare l'indice del carattere LETTERA LATINA A MAIUSCOLA CON accento GRAVE (U+00C0) in una stringa.The following example tries to find the index of the LATIN CAPITAL LETTER A WITH GRAVE character (U+00C0) in a string. Tuttavia, questo carattere può essere rappresentato in due modi diversi: come singola unità di codice (U+00C0) o come carattere composito (due unità di codice: U+0021 e U+007E).However, this character can be represented in two different ways: as a single code unit (U+00C0) or as a composite character (two code units: U+0021 and U+007E). In questo caso, il carattere è rappresentato nell'istanza della stringa da due oggetti Char, U+0021 e U+007E.In this case, the character is represented in the string instance by two Char objects, U+0021 and U+007E. Il codice di esempio chiama gli overload String.IndexOf(Char) e String.IndexOf(String) per trovare la posizione del carattere incluso nell'istanza della stringa, ma questi restituiscono risultati diversi.The example code calls the String.IndexOf(Char) and String.IndexOf(String) overloads to find the position of this character in the string instance, but these return different results. La prima chiamata al metodo dispone di un argomento Char; esegue un confronto ordinale e pertanto non può trovare una corrispondenza.The first method call has a Char argument; it performs an ordinal comparison and therefore cannot find a match. La seconda chiamata dispone di un argomento String; esegue un confronto dipendente dalle impostazioni cultura e pertanto trova una corrispondenza.The second call has a String argument; it performs a culture-sensitive comparison and therefore finds a match.

using System;
using System.Globalization;
using System.Threading;

public class Example
{
   public static void Main()
   {
      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 Example
   Public Sub Main()
      Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("pl-PL")
      Dim composite As String = ChrW(&h0041) + ChrW(&H0300) 
      Console.WriteLine("Comparing using Char:   {0}", composite.IndexOf(ChrW(&h00C0)))
      Console.WriteLine("Comparing using String: {0}", composite.IndexOf(ChrW(&h00C0).ToString()))
   End Sub 
End Module
' The example displays the following output:
'       Comparing using Char:   -1
'       Comparing using String: 0

È possibile evitare parte dell'ambiguità di questo esempio (chiamate a due overload simili di un metodo che restituisce risultati diversi) chiamando un overload che include un parametro StringComparison, ad esempio il metodo String.IndexOf(String, StringComparison) o String.LastIndexOf(String, StringComparison).You can avoid some of the ambiguity of this example (calls to two similar overloads of a method returning different results) by calling an overload that includes a StringComparison parameter, such as the String.IndexOf(String, StringComparison) or String.LastIndexOf(String, StringComparison) method.

Tuttavia, le ricerche non sono sempre dipendenti dalle impostazioni cultura.However, searches are not always culture-sensitive. Se lo scopo della ricerca è prendere una decisione relativa alla sicurezza oppure consentire o impedire l'accesso ad alcune risorse, il confronto deve essere ordinale, come descritto nella sezione successiva.If the purpose of the search is to make a security decision or to allow or disallow access to some resource, the comparison should be ordinal, as discussed in the next section.

Test dell'uguaglianza delle stringheTesting Strings for Equality

Se si vuole verificare l'uguaglianza di due stringhe anziché determinare la relativa modalità di confronto nell'ordinamento, usare il metodo String.Equals anziché un metodo di confronto di stringhe, quale String.Compare o CompareInfo.Compare.If you want to test two strings for equality rather than determining how they compare in the sort order, use the String.Equals method instead of a string comparison method such as String.Compare or CompareInfo.Compare.

I confronti di uguaglianza in genere vengono eseguiti i per accedere ad alcune risorse in modo condizionale.Comparisons for equality are typically performed to access some resource conditionally. Ad esempio, è possibile eseguire un confronto di uguaglianza per verificare una password o l'esistenza di un file.For example, you might perform a comparison for equality to verify a password or to confirm that a file exists. Confronti non linguistici di questo tipo devono essere ordinali anziché dipendenti dalle impostazioni cultura.Such non-linguistic comparisons should always be ordinal rather than culture-sensitive. In genere, è consigliabile chiamare il metodo String.Equals(String, StringComparison) dell'istanza o il metodo String.Equals(String, String, StringComparison) statico con un valore StringComparison.Ordinal per stringhe quali le password e un valore StringComparison.OrdinalIgnoreCase per stringhe quali i nomi file o gli URI.In general, you should call the instance String.Equals(String, StringComparison) method or the static String.Equals(String, String, StringComparison) method with a value of StringComparison.Ordinal for strings such as passwords, and a value of StringComparison.OrdinalIgnoreCase for strings such as file names or URIs.

I confronti di uguaglianza talvolta comportano ricerche o confronti delle sottostringhe anziché chiamate al metodo String.Equals.Comparisons for equality sometimes involve searches or substring comparisons rather than calls to the String.Equals method. In alcuni casi, si potrebbe usare la ricerca di una sottostringa per determinare se la sottostringa è uguale a un'altra stringa.In some cases, you may use a substring search to determine whether that substring equals another string. Se lo scopo di questo confronto non è linguistico, anche la ricerca deve essere ordinale anziché dipendente dalle impostazioni cultura.If the purpose of this comparison is non-linguistic, the search should also be ordinal rather than culture-sensitive.

Nell'esempio seguente viene illustrato il rischio di una ricerca dipendente dalle impostazioni cultura su dati non linguistici.The following example illustrates the danger of a culture-sensitive search on non-linguistic data. Il metodo AccessesFileSystem è progettato per impedire l'accesso al file system agli URI che iniziano con la sottostringa "FILE".The AccessesFileSystem method is designed to prohibit file system access for URIs that begin with the substring "FILE". A tale scopo, esegue un confronto dipendente dalle impostazioni cultura, con distinzione tra maiuscole e minuscole, dell'inizio dell'URI con la stringa "FILE".To do this, it performs a culture-sensitive, case-insensitive comparison of the beginning of the URI with the string "FILE". Poiché un'URI che accede al file system può iniziare con "FILE:" o "file:", il presupposto implicito è che la "i" (U+0069) è sempre l'equivalente minuscolo di "I" (U+0049).Because a URI that accesses the file system can begin with either "FILE:" or "file:", the implicit assumption is that that "i" (U+0069) is always the lowercase equivalent of "I" (U+0049). Tuttavia, in turco e azero, la versione maiuscola della "i" è "İ" (U+0130).However, in Turkish and Azerbaijani, the uppercase version of "i" is "İ" (U+0130). A causa di questa discrepanza, il confronto dipendente dalle impostazioni cultura consente l'accesso al file system anche se non dovesse essere consentito.Because of this discrepancy, the culture-sensitive comparison allows file system access when it should be prohibited.

using System;
using System.Globalization;
using System.Threading;

public class Example
{
   public static void Main()
   {
      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 Example
   Public Sub Main()
      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.

È possibile evitare questo problema eseguendo un confronto ordinale che ignora le maiuscole e minuscole, come illustrato nell'esempio di seguito.You can avoid this problem by performing an ordinal comparison that ignores case, as the following example shows.

using System;
using System.Globalization;
using System.Threading;

public class Example
{
   public static void Main()
   {
      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 Example
   Public Sub Main()
      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.

Ordinamento delle stringheOrdering and Sorting Strings

In genere, le stringhe ordinate da visualizzare nell'interfaccia utente devono essere ordinate in base alle impostazioni cultura.Typically, ordered strings that are to be displayed in the user interface should be sorted based on culture. Nella maggior parte dei casi, questi confronti di stringhe vengono gestiti in modo implicito da .NET Framework quando si chiama un metodo che ordina stringhe, ad esempio Array.Sort o List<T>.Sort.For the most part, such string comparisons are handled implicitly by the .NET Framework when you call a method that sorts strings, such as Array.Sort or List<T>.Sort. Per impostazione predefinita, le stringhe vengono ordinate usando le convenzioni di ordinamento delle impostazioni cultura correnti.By default, strings are sorted by using the sorting conventions of the current culture. Nell'esempio seguente viene illustrata la differenza quando viene ordinata una matrice di stringhe usando le convenzioni delle impostazioni cultura inglese (Stati Uniti) e le impostazioni cultura svedese (Svezia).The following example illustrates the difference when an array of strings is sorted by using the conventions of the English (United States) culture and the Swedish (Sweden) culture.

using System;
using System.Globalization;
using System.Threading;

public class Example
{
   public static void Main()
   {
      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 Example
   Public Sub Main()
      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

Il confronto di stringhe dipendenti dalle impostazioni cultura viene definito dall'oggetto CompareInfo, restituito dalla proprietà CultureInfo.CompareInfo delle singole impostazioni cultura.Culture-sensitive string comparison is defined by the CompareInfo object, which is returned by each culture's CultureInfo.CompareInfo property. I confronti di stringhe dipendenti dalle impostazioni cultura che usano gli overload del metodo String.Compare usano anche l'oggetto CompareInfo.Culture-sensitive string comparisons that use the String.Compare method overloads also use the CompareInfo object.

.NET Framework usa tabelle per eseguire ordinamenti dipendenti dalle impostazioni cultura sui dati di tipo stringa.The .NET Framework uses tables to perform culture-sensitive sorts on string data. Il contenuto delle tabelle, che contengono dati sui fattori di ordinamento e sulla normalizzazione delle stringhe, è determinato dalla versione standard Unicode implementata da una determinata versione di .NET Framework.The content of these tables, which contain data on sort weights and string normalization, is determined by the version of the Unicode standard implemented by a particular version of the .NET Framework. Nella tabella riportata di seguito sono elencate le versioni di Unicode implementate dalle versioni specifiche di .NET Framework.The following table lists the versions of Unicode implemented by the specified versions of the .NET Framework. Si noti che l'elenco delle versioni supportate da Unicode si applica soltanto al confronto dei caratteri e all'ordinamento alfabetico; non si applica alla classificazione di caratteri Unicode in base alla categoria.Note that this list of supported Unicode versions applies to character comparison and sorting only; it does not apply to classification of Unicode characters by category. Per altre informazioni, vedere la sezione "Stringhe e standard Unicode" nell'articolo String.For more information, see the "Strings and The Unicode Standard" section in the String article.

Versione di .NET Framework.NET Framework version Sistema operativoOperating system Versione UnicodeUnicode version
.NET Framework 2.0.NET Framework 2.0 Tutti i sistemi operativiAll operating systems Unicode 4.1Unicode 4.1
.NET Framework 3.0.NET Framework 3.0 Tutti i sistemi operativiAll operating systems Unicode 4.1Unicode 4.1
.NET Framework 3.5.NET Framework 3.5 Tutti i sistemi operativiAll operating systems Unicode 4.1Unicode 4.1
.NET Framework 4.NET Framework 4 Tutti i sistemi operativiAll operating systems Unicode 5.0Unicode 5.0
.NET Framework 4.5.NET Framework 4.5 Windows 7Windows 7 Unicode 5.0Unicode 5.0
.NET Framework 4.5.NET Framework 4.5 Windows 8Windows 8 Unicode 6.0Unicode 6.0

In .NET Framework 4.5.NET Framework 4.5 il confronto e l'ordinamento di stringhe dipendono dal sistema operativo.In the .NET Framework 4.5.NET Framework 4.5, string comparison and sorting depends on the operating system. .NET Framework 4.5.NET Framework 4.5 in esecuzione su Windows 7Windows 7 recupera i dati dalle rispettive tabelle che implementano il formato Unicode 5.0.The .NET Framework 4.5.NET Framework 4.5 running on Windows 7Windows 7 retrieves data from its own tables that implement Unicode 5.0. .NET Framework 4.5.NET Framework 4.5 in esecuzione su Windows 8Windows 8 recupera i dati dalle tabelle del sistema operativo che implementano il formato Unicode 6.0.The .NET Framework 4.5.NET Framework 4.5 running on Windows 8Windows 8 retrieves data from operating system tables that implement Unicode 6.0. Se si serializzano i dati ordinati dipendenti dalle impostazioni cultura, è possibile usare la classe SortVersion per determinare se i dati serializzati devono essere ordinati in modo che siano coerenti con .NET Framework e con l'ordinamento del sistema operativo.If you serialize culture-sensitive sorted data, you can use the SortVersion class to determine when your serialized data needs to be sorted so that it is consistent with the .NET Framework and the operating system's sort order. Per un esempio, vedere l'argomento relativo alla classe SortVersion.For an example, see the SortVersion class topic.

Se l'app esegue ordinamenti estesi specifici delle impostazioni cultura di dati stringa, è possibile usare la classe SortKey per confrontare le stringhe.If your app performs extensive culture-specific sorts of string data, you can work with the SortKey class to compare strings. Una chiave di ordinamento riflette i fattori di ordinamento specifici alle impostazioni cultura, inclusi i caratteri alfabetici, i caratteri maiuscoli e minuscoli e i segni diacritici di una determinata stringa.A sort key reflects the culture-specific sort weights, including the alphabetic, case, and diacritic weights of a particular string. Poiché i confronti che usano le chiavi di ordinamento sono binari, risultano più veloci dei confronti che usano un oggetto CompareInfo in modo implicito o esplicito.Because comparisons using sort keys are binary, they are faster than comparisons that use a CompareInfo object either implicitly or explicitly. Si deve creare una chiave di ordinamento specifico delle impostazioni cultura per una determinata stringa passando la stringa al metodo CompareInfo.GetSortKey.You create a culture-specific sort key for a particular string by passing the string to the CompareInfo.GetSortKey method.

L'esempio seguente è simile all'esempio precedente.The following example is similar to the previous example. Tuttavia, anziché chiamare il metodo Array.Sort(Array), che chiama in modo implicito il metodo CompareInfo.Compare, viene definita un'implementazione System.Collections.Generic.IComparer<T> che confronta le chiavi di ordinamento di cui viene creata un'istanza e vengono passate al metodo Array.Sort<T>(T[], IComparer<T>).However, instead of calling the Array.Sort(Array) method, which implicitly calls the CompareInfo.Compare method, it defines an System.Collections.Generic.IComparer<T> implementation that compares sort keys, which it instantiates and passes to the Array.Sort<T>(T[], IComparer<T>) method.

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Threading;

public class SortKeyComparer : IComparer<String>
{
   public int Compare(string str1, string str2)
   {
      SortKey sk1, sk2;
      sk1 = CultureInfo.CurrentCulture.CompareInfo.GetSortKey(str1);         
      sk2 = CultureInfo.CurrentCulture.CompareInfo.GetSortKey(str2); 
      return SortKey.Compare(sk1, sk2);        
   }
}

public class Example
{
   public static void Main()
   {
      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 Example
   Public Sub Main()
      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

Evitare la concatenazione di stringheAvoid String Concatenation

Se possibile, evitare l'uso di stringhe composite che vengono compilate in fase di esecuzione da frasi concatenate.If at all possible, avoid using composite strings that are built at run time from concatenated phrases. Le stringhe composite sono difficili da localizzare, in quanto richiedono spesso un ordine grammaticale nel linguaggio originale dell'app che non è applicabile ad altre lingue localizzate.Composite strings are difficult to localize, because they often assume a grammatical order in the app's original language that does not apply to other localized languages.

Gestione di date e oreHandling Dates and Times

La modalità di gestione dei valori di data e ora dipende se vengono visualizzati nell'interfaccia utente o resi persistenti.How you handle date and time values depends on whether they are displayed in the user interface or persisted. In questa sezione vengono esaminati entrambi gli usi.This section examines both usages. Viene inoltre descritto come gestire le differenze di fuso orario e le operazioni aritmetiche quando si usano date e ore.It also discusses how you can handle time zone differences and arithmetic operations when working with dates and times.

Visualizzazione di date e oreDisplaying Dates and Times

In genere, quando le date e le ore sono visualizzate nell'interfaccia utente, è consigliabile usare le convenzioni di formattazione delle impostazioni cultura dell'utente, definite dalla proprietà CultureInfo.CurrentCulture e dall'oggetto DateTimeFormatInfo restituito dalla proprietà CultureInfo.CurrentCulture.DateTimeFormat.Typically, when dates and times are displayed in the user interface, you should use the formatting conventions of the user's culture, which is defined by the CultureInfo.CurrentCulture property and by the DateTimeFormatInfo object returned by the CultureInfo.CurrentCulture.DateTimeFormat property. Le convenzioni di formattazione delle impostazioni cultura correnti vengono automaticamente usate quando si formatta una data tramite uno di questi metodi:The formatting conventions of the current culture are automatically used when you format a date by using any of these methods:

Nell'esempio seguente vengono visualizzati due volte i dati di tramonto e di alba dell'11 ottobre 2012.The following example displays sunrise and sunset data twice for October 11, 2012. Innanzitutto vengono impostate le impostazioni cultura correnti su Croato (Croazia) e, successivamente, su Inglese (Gran Bretagna).It first sets the current culture to Croatian (Croatia), and then to English (Great Britain). In entrambi i casi, le date e le ore verranno visualizzate nel formato appropriato per le impostazioni cultura specifiche.In each case, the dates and times are displayed in the format that is appropriate for that culture.

using System;
using System.Globalization;
using System.Threading;

public class Example
{
   static DateTime[] dates = { new DateTime(2012, 10, 11, 7, 06, 0),
                        new DateTime(2012, 10, 11, 18, 19, 0) };

   public static void Main()
   {
      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 Example
   Dim dates() As Date = { New Date(2012, 10, 11, 7, 06, 0),
                           New Date(2012, 10, 11, 18, 19, 0) }

   Public Sub Main()
      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

Salvare in modo permanente date e orePersisting Dates and Times

È consigliabile non salvare in modo permanente i valori di data e ora in un formato che può variare in base alle impostazioni cultura.You should never persist date and time data in a format that can vary by culture. Si tratta di un errore di programmazione comune che restituisce dati danneggiati o eccezione di runtime.This is a common programming error that results in either corrupted data or a run-time exception. L'esempio seguente serializza due date, 9 gennaio 2013 e 18 agosto 2013, come stringhe usando le convenzioni di formattazione delle impostazioni cultura inglese (Stati Uniti).The following example serializes two dates, January 9, 2013 and August 18, 2013, as strings by using the formatting conventions of the English (United States) culture. I dati recuperati e analizzati mediante le convenzioni delle impostazioni cultura inglese (Stati Uniti) vengono ripristinati correttamente.When the data is retrieved and parsed by using the conventions of the English (United States) culture, it is successfully restored. Tuttavia, quando viene recuperata e analizzata tramite le convenzioni delle impostazioni cultura inglese (Regno Unito), la prima data viene interpretata in modo errato come 1° settembre e la seconda non viene analizzata perché il calendario gregoriano non dispone di un diciottesimo mese.However, when it is retrieved and parsed by using the conventions of the English (United Kingdom) culture, the first date is wrongly interpreted as September 1, and the second fails to parse because the Gregorian calendar does not have an eighteenth month.

using System;
using System.IO;
using System.Globalization;
using System.Threading;

public class Example
{
   public static void Main()
   {
      // 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 Example
   Public Sub Main()
      ' 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

È possibile evitare questo problema in tre modi:You can avoid this problem in any of three ways:

  • Serializzare la data e l'ora in formato binario anziché come stringa.Serialize the date and time in binary format rather than as a string.

  • Salvare e analizzare la rappresentazione della stringa di data e ora usando una stringa di formato personalizzato uguale, indipendentemente dalle impostazioni cultura dell'utente.Save and parse the string representation of the date and time by using a custom format string that is the same regardless of the user's culture.

  • Salvare la stringa usando le convenzioni di formattazione della cultura invariabile.Save the string by using the formatting conventions of the invariant culture.

L'ultimo approccio viene illustrato nell'esempio seguente.The following example illustrates the last approach. Vengono usate le convenzioni di formattazione della cultura invariabile restituita dalla proprietà statica CultureInfo.InvariantCulture.It uses the formatting conventions of the invariant culture returned by the static CultureInfo.InvariantCulture property.

using System;
using System.IO;
using System.Globalization;
using System.Threading;

public class Example
{
   public static void Main()
   {
      // 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 Example
   Public Sub Main()
      ' 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

Presenza di fuso orario e serializzazioneSerialization and Time Zone Awareness

Un valore di data e ora può avere più interpretazioni, a partire da un'ora generale (Gli archivi vengono aperti il 2 gennaio 2013 alle 9:00) a un momento specifico ("Data di nascita: 2 gennaio 2013 6.32.00").A date and time value can have multiple interpretations, ranging from a general time ("The stores open on January 2, 2013, at 9:00 A.M.") to a specific moment in time ("Date of birth: January 2, 2013 6:32:00 A.M."). Quando un valore di ora rappresenta un momento specifico e si ripristina da un valore serializzato, è necessario assicurarsi che rappresenti lo stesso momento indipendentemente dalla posizione geografica o dal fuso orario dell'utente.When a time value represents a specific moment in time and you restore it from a serialized value, you should ensure that it represents the same moment in time regardless of the user's geographical location or time zone.

L'esempio seguente illustra questo problema.The following example illustrates this problem. Viene salvato un singolo valore locale di data e ora come stringa in tre formati standard ("G" per ora estesa e data generale, "S" per data/ora ordinabile e "O" per data/ora roundtrip), nonché in formato binario.It saves a single local date and time value as a string in three standard formats ("G" for general date long time, "s" for sortable date/time, and "o" for round-trip date/time) as well as in binary format.

using System;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;

public class Example
{
   public static void Main()
   {
      BinaryFormatter formatter = new BinaryFormatter();
       
      DateTime dateOriginal = new DateTime(2013, 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");
      } 
      // Serialize the data as a binary value.
      if (! File.Exists("DateInfo.bin")) {
         FileStream fsIn = new FileStream("DateInfo.bin", FileMode.Create);
         formatter.Serialize(fsIn, dateOriginal);
         fsIn.Close();
         Console.WriteLine("Serialized date to DateInfo.bin");
      }
      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);
      }
      Console.WriteLine();
      
      // Restore the date from binary data.
      FileStream fsOut = new FileStream("DateInfo.bin", FileMode.Open);
      DateTime restoredDate = (DateTime) formatter.Deserialize(fsOut);
      Console.WriteLine("{0} {1}", restoredDate, restoredDate.Kind);
   }
}
Imports System.IO
Imports System.Runtime.Serialization.Formatters.Binary

Module Example
   Public Sub Main()
      Dim formatter As New BinaryFormatter()
      
      ' Serialize a date.
      Dim dateOriginal As Date = #03/30/2013 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()
         Console.WriteLine("Serialized dates to DateInfo.dat")
      End If   
      ' Serialize the date as a binary value.
      If Not File.Exists("DateInfo.bin") Then
         Dim fsIn As New FileStream("DateInfo.bin", FileMode.Create)
         formatter.Serialize(fsIn, dateOriginal)
         fsIn.Close()
         Console.WriteLine("Serialized date to DateInfo.bin")
      End If
      Console.WriteLine()
      
      ' 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
      Console.WriteLine()
      
      ' Restore the date from binary data.
      Dim fsOut As New FileStream("DateInfo.bin", FileMode.Open)
      Dim restoredDate As Date = DirectCast(formatter.Deserialize(fsOut), DateTime)
      Console.WriteLine("{0} {1}", restoredDate, restoredDate.Kind)
   End Sub
End Module

Quando i dati vengono ripristinati in un sistema con lo stesso fuso orario del sistema su cui sono stati serializzati, i valori di data e ora deserializzati riflettono accuratamente il valore originale, come mostra l'output:When the data is restored on a system in the same time zone as the system on which it was serialized, the deserialized date and time values accurately reflect the original value, as the output shows:

'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  

3/30/2013 6:00:00 PM Local  

Tuttavia, se si ripristinano i dati in un sistema con un fuso orario diverso, solo il valore di data e orario formattato con la stringa di formato standard "O" (roundtrip) conserva le informazioni sul fuso orario e pertanto rappresenta lo stesso istante di tempo.However, if you restore the data on a system in a different time zone, only the date and time value that was formatted with the "o" (round-trip) standard format string preserves time zone information and therefore represents the same instant in time. Di seguito è riportato l'output quando i dati relativi a data e ora vengono ripristinati in un sistema con fuso orario standard dell'Europa occidentale:Here's the output when the date and time data is restored on a system in the Romance Standard Time zone:

'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/31/2013 3:00:00 AM Local  

3/30/2013 6:00:00 PM Local  

Per riflettere in modo preciso un valore di data e ora che rappresenta un singolo momento di tempo indipendentemente dal fuso orario del sistema in cui i dati sono deserializzati, è possibile eseguire una delle seguenti operazioni:To accurately reflect a date and time value that represents a single moment of time regardless of the time zone of the system on which the data is deserialized, you can do any of the following:

  • Salvare il valore come stringa usando la stringa di formato standard (round trip) "O".Save the value as a string by using the "o" (round-trip) standard format string. Quindi deserializzarlo nel sistema di destinazione.Then deserialize it on the target system.

  • Convertirlo in UTC e salvarlo come stringa usando la stringa di formato standard "R" (RFC1123).Convert it to UTC and save it as a string by using the "r" (RFC1123) standard format string. Quindi deserializzarlo nel sistema di destinazione e convertirlo in un'ora locale.Then deserialize it on the target system and convert it to local time.

  • Convertirlo in UTC e salvarlo come stringa usando la stringa di formato standard "U" (ordinabile universale).Convert it to UTC and save it as a string by using the "u" (universal sortable) standard format string. Quindi deserializzarlo nel sistema di destinazione e convertirlo in un'ora locale.Then deserialize it on the target system and convert it to local time.

  • Convertirlo in UTC e salvarlo in formato binario.Convert it to UTC and save it in binary format. Quindi deserializzarlo nel sistema di destinazione e convertirlo in un'ora locale.Then deserialize it on the target system and convert it to local time.

Ogni tecnica viene illustrata nell'esempio riportato di seguito.The following example illustrates each technique.

using System;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;

public class Example
{
   public static void Main()
   {
      BinaryFormatter formatter = new BinaryFormatter();
      
      // Serialize a date.
      DateTime dateOriginal = new DateTime(2013, 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();
         Console.WriteLine("Serialized dates to DateInfo.dat");
      }   
      // Serialize the date as a binary value.
      if (! File.Exists("DateInfo2.bin")) {
         FileStream fsIn = new FileStream("DateInfo2.bin", FileMode.Create);
         formatter.Serialize(fsIn, dateOriginal.ToUniversalTime());
         fsIn.Close();
         Console.WriteLine("Serialized date to DateInfo.bin");
      }
      Console.WriteLine();
      
      // 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("'{0}' --> {1} {2}", 
                              dateStrings[ctr], newDate, newDate.Kind);
         }
         else {
            DateTime newLocalDate = newDate.ToLocalTime();
            Console.WriteLine("'{0}' --> {1} {2}", 
                              dateStrings[ctr], newLocalDate, newLocalDate.Kind);
         }
      }
      Console.WriteLine();
      
      // Restore the date from binary data.
      FileStream fsOut = new FileStream("DateInfo2.bin", FileMode.Open);
      DateTime restoredDate = (DateTime) formatter.Deserialize(fsOut);
      restoredDate = restoredDate.ToLocalTime();
      Console.WriteLine("{0} {1}", restoredDate, restoredDate.Kind);
   }
}
Imports System.IO
Imports System.Runtime.Serialization.Formatters.Binary

Module Example
   Public Sub Main()
      Dim formatter As New BinaryFormatter()
      
      ' Serialize a date.
      Dim dateOriginal As Date = #03/30/2013 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()
         Console.WriteLine("Serialized dates to DateInfo.dat")
      End If   
      ' Serialize the date as a binary value.
      If Not File.Exists("DateInfo2.bin") Then
         Dim fsIn As New FileStream("DateInfo2.bin", FileMode.Create)
         formatter.Serialize(fsIn, dateOriginal.ToUniversalTime())
         fsIn.Close()
         Console.WriteLine("Serialized date to DateInfo.bin")
      End If
      Console.WriteLine()
      
      ' 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
      Console.WriteLine()
      
      ' Restore the date from binary data.
      Dim fsOut As New FileStream("DateInfo2.bin", FileMode.Open)
      Dim restoredDate As Date = DirectCast(formatter.Deserialize(fsOut), DateTime)
      restoredDate = restoredDate.ToLocalTime()
      Console.WriteLine("{0} {1}", restoredDate, restoredDate.Kind)
   End Sub
End Module

Quando i dati vengono serializzati in un sistema nel fuso orario del Pacifico e deserializzati in un sistema nel fuso orario dell'Europa occidentale, l'esempio visualizza il seguente output:When the data is serialized on a system in the Pacific Standard Time zone and deserialized on a system in the Romance Standard Time zone, the example displays the following output:

'2013-03-30T18:00:00.0000000-07:00' --> 3/31/2013 3:00:00 AM Local  
'Sun, 31 Mar 2013 01:00:00 GMT' --> 3/31/2013 3:00:00 AM Local  
'2013-03-31 01:00:00Z' --> 3/31/2013 3:00:00 AM Local  

3/31/2013 3:00:00 AM Local  

Per altre informazioni, vedere Conversione degli orari tra fusi orari.For more information, see Converting Times Between Time Zones.

Eseguire l'aritmetica di data e oraPerforming Date and Time Arithmetic

Entrambi i tipi DateTime e DateTimeOffset supportano le operazioni aritmetiche.Both the DateTime and DateTimeOffset types support arithmetic operations. È possibile calcolare la differenza tra due valori di data, oppure aggiungere o sottrarre intervalli di tempo particolari a o da un valore di data.You can calculate the difference between two date values, or you can add or subtract particular time intervals to or from a date value. Tuttavia, nelle operazioni aritmetiche sui valori di data e ora non vengono presi in considerazione i fusi orari e le relative norme di regolazione.However, arithmetic operations on date and time values do not take time zones and time zone adjustment rules into account. Per questo motivo, le operazioni aritmetiche con date e ore sui valori che rappresentano determinati momenti possono restituire risultati imprecisi.Because of this, date and time arithmetic on values that represent moments in time can return inaccurate results.

Ad esempio, la transizione dall'ora solare Pacifico all'ora legale Pacifico si verifica la seconda domenica di marzo, cioè il 10 marzo per l'anno 2013.For example, the transition from Pacific Standard Time to Pacific Daylight Time occurs on the second Sunday of March, which is March 10 for the year 2013. Come illustrato nell'esempio seguente, se si calcola una data e un'ora di 48 ore successive al 9 marzo 2013 ore 10:30.As the following example shows, if you calculate the date and time that is 48 hours after March 9, 2013 at 10:30 A.M. in un sistema con il fuso orario impostato su Ora solare Pacifico, il risultato (11 marzo 2013 ore 10:30) non considera l'adeguamento dell'ora corrispondente.on a system in the Pacific Standard Time zone, the result, March 11, 2013 at 10:30 A.M., does not take the intervening time adjustment into account.

using System;

public class Example
{
   public static void Main()
   {
      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 Example
   Public Sub Main()
      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

Per assicurarsi che un'operazione aritmetica sui valori di data e ora produca risultati accurati, attenersi alla seguente procedura:To ensure that an arithmetic operation on date and time values produces accurate results, follow these steps:

  1. Convertire l'ora nel fuso orario di origine in ora UTC.Convert the time in the source time zone to UTC.

  2. Eseguire l'operazione aritmetica.Perform the arithmetic operation.

  3. Se il risultato è un valore di data e ora, convertirlo dall'ora UTC all'ora del fuso orario di origine.If the result is a date and time value, convert it from UTC to the time in the source time zone.

L'esempio seguente è simile a quello precedente, con la differenza che segue questi tre passaggi correttamente per aggiungere 48 ore alle 10.30 del 9 marzo 2013.The following example is similar to the previous example, except that it follows these three steps to correctly add 48 hours to March 9, 2013 at 10:30 A.M.

using System;

public class Example
{
   public static void Main()
   {
      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 Example
   Public Sub Main()
      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

Per altre informazioni, vedere Esecuzione di operazioni aritmetiche con date e ore.For more information, see Performing Arithmetic Operations with Dates and Times.

Utilizzo dei nomi dipendenti delle impostazioni cultura per gli elementi di datiUsing Culture-Sensitive Names for Date Elements

È possibile che l'app debba visualizzare il nome del mese o il giorno della settimana.Your app may need to display the name of the month or the day of the week. A tale scopo, il codice come il seguente è comune.To do this, code such as the following is common.

using System;

public class Example
{
   public static void Main()
   {
      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 Example
   Public Sub Main()
      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.

Tuttavia, tramite il codice vengono restituiti sempre i nomi dei giorni della settimana in inglese.However, this code always returns the names of the days of the week in English. Il codice che estrae il nome del mese è spesso più flessibile.Code that extracts the name of the month is often even more inflexible. Spesso si presuppone un calendario di dodici mesi con i nomi dei mesi in una lingua specifica.It frequently assumes a twelve-month calendar with names of months in a specific language.

Usando le stringhe di formato di data e ora personalizzate o le proprietà dell'oggetto DateTimeFormatInfo, è facile estrarre le stringhe che riflettono i nomi dei giorni della settimana o dei mesi nelle impostazioni cultura dell'utente, come illustrato nell'esempio seguente.By using custom date and time format strings or the properties of the DateTimeFormatInfo object, it is easy to extract strings that reflect the names of days of the week or months in the user's culture, as the following example illustrates. Vengono impostate le impostazioni cultura correnti su Francese (Francia) e vengono visualizzati il nome del giorno della settimana e il nome del mese per il 1° luglio 2013.It changes the current culture to French (France) and displays the name of the day of the week and the name of the month for July 1, 2013.

using System;
using System.Globalization;
using System.Threading;

public class Example
{
   public static void Main()
   {
      // Set the current thread culture to French (France).
      Thread.CurrentThread.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 Example
   Public Sub Main()
      ' Set the current thread culture to French (France).
      Thread.CurrentThread.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.

Gestione dei valori numericiHandling Numeric Values

La gestione di numeri dipende se vengono visualizzati nell'interfaccia utente o resi persistenti.The handling of numbers depends on whether they are displayed in the user interface or persisted. In questa sezione vengono esaminati entrambi gli usi.This section examines both usages.

Nota

Nelle operazioni di analisi e formattazione, .NET Framework riconosce solo i caratteri latini di base da 0 a 9 (da U+0030 a U+0039) come cifre numeriche.In parsing and formatting operations, the .NET Framework recognizes only the Basic Latin characters 0 through 9 (U+0030 through U+0039) as numeric digits.

Visualizzazione di valori numericiDisplaying Numeric Values

In genere, quando i numeri sono visualizzati nell'interfaccia utente, è consigliabile usare le convenzioni di formattazione delle impostazioni cultura dell'utente, definite nella proprietà CultureInfo.CurrentCulture e dall'oggetto NumberFormatInfo restituito dalla proprietà CultureInfo.CurrentCulture.NumberFormat.Typically, when numbers are displayed in the user interface, you should use the formatting conventions of the user's culture, which is defined by the CultureInfo.CurrentCulture property and by the NumberFormatInfo object returned by the CultureInfo.CurrentCulture.NumberFormat property. Le convenzioni di formattazione delle impostazioni cultura correnti vengono automaticamente usate quando si formatta una data tramite uno dei seguenti metodi:The formatting conventions of the current culture are automatically used when you format a date by using any of the following methods:

  • Il metodo ToString senza parametri di qualsiasi tipo numericoThe parameterless ToString method of any numeric type

  • Il metodo ToString(String) di qualsiasi tipo numerico, che include una stringa di formato come argomentoThe ToString(String) method of any numeric type, which includes a format string as an argument

  • La funzionalità di formattazione composita, quando viene usata con valori numericiThe composite formatting feature, when it is used with numeric values

L'esempio seguente consente di visualizzare la temperatura mensile media di Parigi, Francia.The following example displays the average temperature per month in Paris, France. Innanzitutto vengono impostate le impostazioni cultura correnti su Francese (Francia) prima di visualizzare i dati e, successivamente, vengono impostate su Inglese (Stati Uniti).It first sets the current culture to French (France) before displaying the data, and then sets it to English (United States). In ogni caso, le temperature e i nomi dei mesi verranno visualizzati nel formato appropriato per le impostazioni cultura in questione.In each case, the month names and temperatures are displayed in the format that is appropriate for that culture. Si noti che nelle due impostazioni cultura vengono usati separatori decimali diversi per il valore della temperatura.Note that the two cultures use different decimal separators in the temperature value. Si noti inoltre che in questo esempio viene usata la stringa di formato di data e ora personalizzata "MMMM" per visualizzare il nome completo dei mesi e che viene allocata la quantità di spazio appropriata per il nome del mese nella stringa di risultato determinando la lunghezza del nome del mese più lungo nella matrice DateTimeFormatInfo.MonthNames.Also note that the example uses the "MMMM" custom date and time format string to display the full month name, and that it allocates the appropriate amount of space for the month name in the result string by determining the length of the longest month name in the DateTimeFormatInfo.MonthNames array.

using System;
using System.Globalization;
using System.Threading;

public class Example
{
   public static void Main()
   {
      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 Example
   Public Sub Main()
      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

Salvare in modo permanente i valori numericiPersisting Numeric Values

È consigliabile non salvare in maniera permanente i dati numerici in un formato specifico delle impostazioni cultura.You should never persist numeric data in a culture-specific format. Si tratta di un errore di programmazione comune che restituisce dati danneggiati o eccezione di runtime.This is a common programming error that results in either corrupted data or a run-time exception. L'esempio seguente genera dieci numeri a virgola mobile casuali e li serializza come stringhe usando le convenzioni di formattazione delle impostazioni cultura della lingua inglese (Stati Uniti).The following example generates ten random floating-point numbers, and then serializes them as strings by using the formatting conventions of the English (United States) culture. I dati recuperati e analizzati mediante le convenzioni delle impostazioni cultura inglese (Stati Uniti) vengono ripristinati correttamente.When the data is retrieved and parsed by using the conventions of the English (United States) culture, it is successfully restored. Tuttavia, quando vengono recuperati e analizzati usando le convenzioni delle impostazioni cultura Francese (Francia), nessuno dei numeri può essere analizzato in quanto vengono usati separatori decimali diversi nelle impostazioni cultura.However, when it is retrieved and parsed by using the conventions of the French (France) culture, none of the numbers can be parsed because the cultures use different decimal separators.

using System;
using System.Globalization;
using System.IO;
using System.Threading;

public class Example
{
   public static void Main()
   {
      // 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 Example
   Public Sub Main()
      ' 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'

Per evitare questo problema, usare una delle seguenti tecniche:To avoid this problem, you can use one of these techniques:

  • Salvare e analizzare la rappresentazione di stringa del numero usando una stringa di formato personalizzata uguale indipendentemente dalle impostazioni cultura dell'utente.Save and parse the string representation of the number by using a custom format string that is the same regardless of the user's culture.

  • Salvare il numero come stringa usando le convenzioni di formattazione della lingua inglese restituita dalla proprietà CultureInfo.InvariantCulture.Save the number as a string by using the formatting conventions of the invariant culture, which is returned by the CultureInfo.InvariantCulture property.

  • Serializzare il numero in formato di file binario anziché in formato stringa.Serialize the number in binary instead of string format.

L'ultimo approccio viene illustrato nell'esempio seguente.The following example illustrates the last approach. Viene serializzata la matrice di valori Double e, successivamente, i valori in questione vengono deserializzati e visualizzati usando le convenzioni di formattazione delle impostazioni cultura inglese (Stati Uniti) e francese (Francia).It serializes the array of Double values, and then deserializes and displays them by using the formatting conventions of the English (United States) and French (France) cultures.

using System;
using System.Globalization;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Threading;

public class Example
{
   public static void Main()
   {
      // Create ten random doubles.
      Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("en-US");
      double[] numbers = GetRandomNumbers(10);
      DisplayRandomNumbers(numbers);
      
      // Serialize the array.
      FileStream fsIn = new FileStream("randoms.dat", FileMode.Create);
      BinaryFormatter formatter = new BinaryFormatter();
      formatter.Serialize(fsIn, numbers);
      fsIn.Close();
      
      // Read the persisted data.
      FileStream fsOut = new FileStream("randoms.dat", FileMode.Open);
      double[] numbers1 = (Double[]) formatter.Deserialize(fsOut);      
      fsOut.Close();
      
      // Display the data using the conventions of the en-US culture.
      Console.WriteLine("Current Culture: {0}", 
                        Thread.CurrentThread.CurrentCulture.DisplayName); 
      DisplayRandomNumbers(numbers1);
                                             
      // 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); 
      DisplayRandomNumbers(numbers1);
   }

   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:
//       932.10070623648392
//       96.868112262742642
//       857.111520067375
//       771.37727233179726
//       262.65733840999064
//       387.00796914613244
//       557.49389788019187
//       83.79498919648816
//       957.31006048494487
//       996.54487892824454
//       
//       Current Culture: English (United States)
//       932.10070623648392
//       96.868112262742642
//       857.111520067375
//       771.37727233179726
//       262.65733840999064
//       387.00796914613244
//       557.49389788019187
//       83.79498919648816
//       957.31006048494487
//       996.54487892824454
//       
//       Current Culture: French (France)
//       932,10070623648392
//       96,868112262742642
//       857,111520067375
//       771,37727233179726
//       262,65733840999064
//       387,00796914613244
//       557,49389788019187
//       83,79498919648816
//       957,31006048494487
//       996,54487892824454
Imports System.Globalization
Imports System.IO
Imports System.Runtime.Serialization.Formatters.Binary
Imports System.Threading

Module Example
   Public Sub Main()
      ' Create ten random doubles.
      Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("en-US")
      Dim numbers() As Double = GetRandomNumbers(10)
      DisplayRandomNumbers(numbers)
      
      ' Serialize the array.
      Dim fsIn As New FileStream("randoms.dat", FileMode.Create)
      Dim formatter As New BinaryFormatter()
      formatter.Serialize(fsIn, numbers)
      fsIn.Close()
      
      ' Read the persisted data.
      Dim fsOut AS New FileStream("randoms.dat", FileMode.Open)
      Dim numbers1() As Double = DirectCast(formatter.Deserialize(fsOut), Double())      
      fsOut.Close()
      
      ' Display the data using the conventions of the en-US culture.
      Console.WriteLine("Current Culture: {0}", 
                        Thread.CurrentThread.CurrentCulture.DisplayName) 
      DisplayRandomNumbers(numbers1)
                                             
      ' 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) 
      DisplayRandomNumbers(numbers1)
   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:
'       932.10070623648392
'       96.868112262742642
'       857.111520067375
'       771.37727233179726
'       262.65733840999064
'       387.00796914613244
'       557.49389788019187
'       83.79498919648816
'       957.31006048494487
'       996.54487892824454
'       
'       Current Culture: English (United States)
'       932.10070623648392
'       96.868112262742642
'       857.111520067375
'       771.37727233179726
'       262.65733840999064
'       387.00796914613244
'       557.49389788019187
'       83.79498919648816
'       957.31006048494487
'       996.54487892824454
'       
'       Current Culture: French (France)
'       932,10070623648392
'       96,868112262742642
'       857,111520067375
'       771,37727233179726
'       262,65733840999064
'       387,00796914613244
'       557,49389788019187
'       83,79498919648816
'       957,31006048494487
'       996,54487892824454

La serializzazione dei valori di valuta è un caso speciale.Serializing currency values is a special case. Poiché un valore di valuta dipende dall'unità di valuta in cui viene espresso, non è opportuno considerarlo un valore numerico indipendente.Because a currency value depends on the unit of currency in which it is expressed; it makes little sense to treat it as an independent numeric value. Tuttavia, se si salva un valore di valuta come stringa formattata in cui è incluso un simbolo di valuta, non è possibile deserializzarlo in un sistema in cui le impostazioni cultura predefinite usano un simbolo di valuta diverso, come illustrato nell'esempio di seguito.However, if you save a currency value as a formatted string that includes a currency symbol, it cannot be deserialized on a system whose default culture uses a different currency symbol, as the following example shows.

using System;
using System.Globalization;
using System.IO;
using System.Threading;

public class Example
{
   public static void Main()
   {
      // 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 Example
   Public Sub Main()
      ' 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'

In alternativa, serializzare il valore numerico con alcune informazioni relative alle impostazioni cultura, ad esempio il nome delle impostazioni cultura, in modo che il valore e il relativo simbolo di valuta possano essere deserializzati indipendentemente dalle impostazioni cultura correnti.Instead, you should serialize the numeric value along with some cultural information, such as the name of the culture, so that the value and its currency symbol can be deserialized independently of the current culture. Nell'esempio seguente viene definita una struttura CurrencyValue con due membri: il valore Decimal e il nome delle impostazioni cultura a cui appartiene il valore.The following example does that by defining a CurrencyValue structure with two members: the Decimal value and the name of the culture to which the value belongs.

using System;
using System.Globalization;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Threading;

public class Example
{
   public static void Main()
   {
      // 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); 
     
      // Serialize the currency data.
      BinaryFormatter bf = new BinaryFormatter();
      FileStream fw = new FileStream("currency.dat", FileMode.Create);
      CurrencyValue data = new CurrencyValue(value, CultureInfo.CurrentCulture.Name);
      bf.Serialize(fw, data);
      fw.Close();
      Console.WriteLine();
      
      // Change the current thread culture.
      Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("en-GB");
      Console.WriteLine("Current Culture: {0}", CultureInfo.CurrentCulture.DisplayName);
      
      // Deserialize the data.
      FileStream fr = new FileStream("currency.dat", FileMode.Open);
      CurrencyValue restoredData = (CurrencyValue) bf.Deserialize(fr);
      fr.Close();
      
      // Display the original value.
      CultureInfo culture = CultureInfo.CreateSpecificCulture(restoredData.CultureName);
      Console.WriteLine("Currency Value: {0}", restoredData.Amount.ToString("C2", culture));
   }
}

[Serializable] internal struct CurrencyValue
{
   public CurrencyValue(Decimal amount, string name)
   {
      this.Amount = amount; 
      this.CultureName = name;
   }
   
   public Decimal Amount;
   public string CultureName;      
}
// 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.IO
Imports System.Runtime.Serialization.Formatters.Binary
Imports System.Threading

<Serializable> Friend Structure CurrencyValue
   Public Sub New(amount As Decimal, name As String)
      Me.Amount = amount 
      Me.CultureName = name
   End Sub
   
   Public Amount As Decimal
   Public CultureName As String      
End Structure

Module Example
   Public Sub Main()
      ' 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 bf As New BinaryFormatter()
      Dim fw As New FileStream("currency.dat", FileMode.Create)
      Dim data As New CurrencyValue(value, CultureInfo.CurrentCulture.Name)
      bf.Serialize(fw, data)
      fw.Close()
      Console.WriteLine()
      
      ' Change the current thread culture.
      Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("en-GB")
      Console.WriteLine("Current Culture: {0}", CultureInfo.CurrentCulture.DisplayName)
      
      ' Deserialize the data.
      Dim fr AS New FileStream("currency.dat", FileMode.Open)
      Dim restoredData As CurrencyValue = CType(bf.Deserialize(fr), CurrencyValue)
      fr.Close()
      
      ' Display the original 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

Utilizzo di impostazioni specifiche delle impostazioni culturaWorking with Culture-Specific Settings

In .NET Framework la classe CultureInfo rappresenta particolari impostazioni cultura o area.In the .NET Framework, the CultureInfo class represents a particular culture or region. Alcune proprietà restituiscono oggetti che includono informazioni specifiche su alcuni aspetti delle impostazioni cultura:Some of its properties return objects that provide specific information about some aspect of a culture:

In genere, non fare supposizioni sui valori della proprietà CultureInfo specifiche e sui relativi oggetti correlati.In general, do not make any assumptions about the values of specific CultureInfo properties and their related objects. Considerare invece i dati specifici delle impostazioni cultura come elementi soggetti a modifiche, per questi motivi:Instead, you should view culture-specific data as subject to change, for these reasons:

  • I singoli valori di proprietà sono soggetti a modifiche e revisioni nel tempo, poiché i dati vengono corretti, si rendono disponibili dati migliori o si apportano modifiche di convenzioni specifiche delle impostazioni cultura.Individual property values are subject to change and revision over time, as data is corrected, better data becomes available, or culture-specific conventions change.

  • I singoli valori di proprietà possono variare tra le diverse versioni di .NET Framework o del sistema operativo.Individual property values may vary across versions of the .NET Framework or operating system versions.

  • .NET Framework supporta impostazioni cultura sostitutive.The .NET Framework supports replacement cultures. Ciò consente di definire nuove impostazioni cultura personalizzate che completano le impostazioni cultura standard esistenti o li sostituiscono completamente.This makes it possible to define a new custom culture that either supplements existing standard cultures or completely replaces an existing standard culture.

  • L'utente può personalizzare le impostazioni specifiche di una cultura usando l'app Area e lingua nel Pannello di controllo.The user can customize culture-specific settings by using the Region and Language app in Control Panel. Quando viene creata un'istanza di un oggetto CultureInfo, è possibile determinare se rifletta le personalizzazioni dell'utente chiamando il costruttore CultureInfo.CultureInfo(String, Boolean).When you instantiate a CultureInfo object, you can determine whether it reflects these user customizations by calling the CultureInfo.CultureInfo(String, Boolean) constructor. In genere, per le app degli utenti finali, è necessario rispettare le preferenze dell'utente in modo da offrirgli i dati in un formato che l'utente si aspetta.Typically, for end-user apps, you should respect user preferences so that the user is presented with data in a format that he or she expects.

Vedere ancheSee Also

Globalizzazione e localizzazioneGlobalization and Localization
Procedure consigliate per l'uso delle stringheBest Practices for Using Strings