.NET에서 문자열 사용에 대한 모범 사례Best Practices for Using Strings in .NET

.NET에서는 지역화된 애플리케이션과 전역화된 애플리케이션을 개발하기 위한 광범위한 지원을 제공하고 문자열 정렬 및 표시와 같은 일반적인 작업을 수행할 때 현재 문화권이나 특정 문화권의 규칙을 쉽게 적용할 수 있습니다..NET provides extensive support for developing localized and globalized applications, and makes it easy to apply the conventions of either the current culture or a specific culture when performing common operations such as sorting and displaying strings. 그러나 문자열 정렬 및 비교가 항상 문화권이 구분되는 작업은 아닙니다.But sorting or comparing strings is not always a culture-sensitive operation. 예를 들어 애플리케이션에서 내부적으로 사용되는 문자열은 대기 모든 문화권에서 동일하게 처리해야 합니다.For example, strings that are used internally by an application typically should be handled identically across all cultures. XML 태그, HTML 태그, 사용자 이름, 파일 경로 및 시스템 개체 이름과 같이 문화권을 구분하지 않는 문자열 데이터가 문화권이 구분되는 것처럼 해석되면 애플리케이션 코드에는 감지하기 어려운 버그, 성능 저하 및 경우에 따라 보안 문제가 발생할 수 있습니다.When culturally independent string data, such as XML tags, HTML tags, user names, file paths, and the names of system objects, are interpreted as if they were culture-sensitive, application code can be subject to subtle bugs, poor performance, and, in some cases, security issues.

이 항목에서는 .NET의 문자열 정렬, 비교 및 대/소문자 구분 방법을 살펴보고, 적절한 문자열 처리 방법 선택을 위한 권장 사항을 제공하고, 문자열 처리 방법에 대한 추가 정보를 제공합니다.This topic examines the string sorting, comparison, and casing methods in .NET, presents recommendations for selecting an appropriate string-handling method, and provides additional information about string-handling methods. 또한 숫자 데이터 및 날짜/시간 데이터와 같은 형식이 지정된 데이터를 표시 및 스토리지를 위해 처리하는 방법을 살펴봅니다.It also examines how formatted data, such as numeric data and date and time data, is handled for display and for storage.

문자열 사용에 대한 권장 사항Recommendations for string usage

.NET으로 개발하는 경우 문자열을 사용할 때 다음과 같은 간단한 권장 사항을 따르세요.When you develop with .NET, follow these simple recommendations when you use strings:

문자열을 사용할 때 다음 사례를 사용하지 마세요.Avoid the following practices when you use strings:

  • 문자열 작업에 대한 문자열 비교 규칙을 명시적 또는 암시적으로 지정하지 않는 오버로드를 사용하지 마세요.Do not use overloads that do not explicitly or implicitly specify the string comparison rules for string operations.
  • 대부분 경우에 StringComparison.InvariantCulture 를 기준으로 한 문자열 작업을 사용하지 마세요.Do not use string operations based on StringComparison.InvariantCulture in most cases. 몇 가지 예외의 하나는 언어적으로 의미가 있지만 문화적으로 독립적인 데이터를 유지하는 경우입니다.One of the few exceptions is when you are persisting linguistically meaningful but culturally agnostic data.
  • String.Compare 또는 CompareTo 메서드의 오버로드 및 두 문자열이 같은지를 확인하기 위한 반환 값 0에 대한 테스트를 사용하지 마세요.Do not use an overload of the String.Compare or CompareTo method and test for a return value of zero to determine whether two strings are equal.
  • 문자열 양식에서 숫자 데이터나 날짜 및 시간 데이터를 유지하는 데 문화권이 구분되는 형식 지정을 사용하지 마세요.Do not use culture-sensitive formatting to persist numeric data or date and time data in string form.

명시적으로 문자열 비교 지정Specifying string comparisons explicitly

.NET의 문자열 조작 메서드는 대부분 오버로드됩니다.Most of the string manipulation methods in .NET are overloaded. 일반적으로 오버로드 하나 이상은 기본 설정을 그대로 사용하지만, 다른 오버로드는 기본값을 사용하지 않고 문자열을 비교 및 조작하는 정확한 방법을 정의합니다.Typically, one or more overloads accept default settings, whereas others accept no defaults and instead define the precise way in which strings are to be compared or manipulated. 기본값을 사용하지 않는 대부분 메서드에는 문화권 및 사례별로 문자열 비교에 대한 규칙을 명시적으로 지정하는 열거형인 StringComparison형식 매개 변수가 포함됩니다.Most of the methods that do not rely on defaults include a parameter of type StringComparison, which is an enumeration that explicitly specifies rules for string comparison by culture and case. 다음 표에서는 StringComparison 열거형 멤버에 대해 설명합니다.The following table describes the StringComparison enumeration members.

StringComparison 멤버StringComparison member 설명Description
CurrentCulture 현재 문화권을 사용하여 대/소문자를 구분하는 비교를 수행합니다.Performs a case-sensitive comparison using the current culture.
CurrentCultureIgnoreCase 현재 문화권을 사용하여 대/소문자를 구분하지 않는 비교를 수행합니다.Performs a case-insensitive comparison using the current culture.
InvariantCulture 고정 문화권을 사용하여 대/소문자를 구분하는 비교를 수행합니다.Performs a case-sensitive comparison using the invariant culture.
InvariantCultureIgnoreCase 고정 문화권을 사용하여 대/소문자를 구분하지 않는 비교를 수행합니다.Performs a case-insensitive comparison using the invariant culture.
Ordinal 서수 비교를 수행합니다.Performs an ordinal comparison.
OrdinalIgnoreCase 대소문자를 구분하지 않는 서수 비교를 수행합니다.Performs a case-insensitive ordinal comparison.

예를 들어 문자 또는 문자열과 일치하는 IndexOf 개체의 하위 문자열 인덱스를 반환하는 String 메서드에는 다음과 같은 오버로드 9개가 포함됩니다.For example, the IndexOf method, which returns the index of a substring in a String object that matches either a character or a string, has nine overloads:

다음 이유로 기본값을 사용하지 않는 오버로드를 선택하는 것이 좋습니다.We recommend that you select an overload that does not use default values, for the following reasons:

  • 기본 매개 변수가 있는 일부 오버로드(문자열 인스턴스에서 Char 을 검색하는 오버로드)는 서수 비교를 수행하지만, 다른 오버로드(문자열 인스턴스에서 문자열을 검색하는 오버로드)는 문화권이 구분됩니다.Some overloads with default parameters (those that search for a Char in the string instance) perform an ordinal comparison, whereas others (those that search for a string in the string instance) are culture-sensitive. 어떤 메서드가 어떤 기본값을 사용하는지 기억하기 어렵고 오버로드를 혼동하기 쉽습니다.It is difficult to remember which method uses which default value, and easy to confuse the overloads.

  • 메서드 호출에 대해 기본값을 사용하는 코드의 의도는 분명하지 않습니다.The intent of the code that relies on default values for method calls is not clear. 기본값을 사용하는 다음 예제에서는 개발자가 실제로 두 문자열의 서수 또는 언어 비교를 의도했는지 또는 protocol 과 "http" 간의 대/소문자 차이로 인해 같음 테스트에서 false형식 매개 변수가 포함된 메서드 오버로드를 호출하는 작업입니다.In the following example, which relies on defaults, it is difficult to know whether the developer actually intended an ordinal or a linguistic comparison of two strings, or whether a case difference between protocol and "http" might cause the test for equality to return false.

    string protocol = GetProtocol(url);       
    if (String.Equals(protocol, "http")) {
       // ...Code to handle HTTP protocol.
    }
    else {
       throw new InvalidOperationException();
    }
    
    Dim protocol As String = GetProtocol(url)       
    If String.Equals(protocol, "http") Then
       ' ...Code to handle HTTP protocol.
    Else
       Throw New InvalidOperationException()
    End If   
    

일반적으로 기본값을 사용하지 않는 메서드를 사용하면 코드의 의도가 분명해지므로 이 메서드를 호출하는 것이 좋습니다.In general, we recommend that you call a method that does not rely on defaults, because it makes the intent of the code unambiguous. 이 메서드를 사용하면 코드를 더 쉽게 읽을 수 있고 더 쉽게 디버그 및 유지 관리할 수도 있습니다.This, in turn, makes the code more readable and easier to debug and maintain. 다음 예제에서는 이전 예제와 관련된 질문을 해결합니다.The following example addresses the questions raised about the previous example. 예제에서는 서수 비교가 사용되고 대/소문자 차이가 무시됩니다.It makes it clear that ordinal comparison is used and that differences in case are ignored.

string protocol = GetProtocol(url);       
if (String.Equals(protocol, "http", StringComparison.OrdinalIgnoreCase)) {
   // ...Code to handle HTTP protocol.
}
else {
   throw new InvalidOperationException();
}
Dim protocol As String = GetProtocol(url)       
If String.Equals(protocol, "http", StringComparison.OrdinalIgnoreCase) Then
   ' ...Code to handle HTTP protocol.
Else
   Throw New InvalidOperationException()
End If   

문자열 비교 세부 정보The details of string comparison

문자열 비교는 특히 정렬 및 같음 테스트와 같은 다양한 문자열 관련 작업의 핵심입니다.String comparison is the heart of many string-related operations, particularly sorting and testing for equality. 결정된 순서로 문자열 정렬: 정렬된 문자열 목록에서 "my"가 "string" 앞에 나타나면 "my"가 "string"과 같거나 작은지 비교해야 합니다.Strings sort in a determined order: If "my" appears before "string" in a sorted list of strings, "my" must compare less than or equal to "string". 또한 비교는 암시적으로 같음을 정의합니다.Additionally, comparison implicitly defines equality. 비교 작업은 같은 것으로 판단되는 문자열에 대해 0을 반환합니다.The comparison operation returns zero for strings it deems equal. 다른 문자열보다 작은 문자열이 없다고 해석하는 것이 적절합니다.A good interpretation is that neither string is less than the other. 문자열과 관련된 대부분 의미 있는 작업에는 다른 문자열과 비교 및 잘 정의된 정렬 작업 실행이라는 두 가지 절차가 둘 다 또는 두 가지 중 하나가 포함됩니다.Most meaningful operations involving strings include one or both of these procedures: comparing with another string, and executing a well-defined sort operation.

참고

Windows 운영 체제에 대한 정렬 및 비교 작업에 사용되는 문자 가중치에 대한 정보를 포함하는 텍스트 파일 집합인 정렬 가중치 테이블 및 Linux 및 macOS용 정렬 가중치 테이블의 최신 버전인 기본 유니코드 데이터 정렬 요소 테이블을 다운로드할 수 있습니다.You can download the Sorting Weight Tables, a set of text files that contain information on the character weights used in sorting and comparison operations for Windows operating systems, and the Default Unicode Collation Element Table, the latest version of the sort weight table for Linux and macOS. Linux 및 macOS에서 정렬 가중치 테이블의 특정 버전은 시스템에 설치된 International Components for Unicode 라이브러리 버전에 따라 달라집니다.The specific version of the sort weight table on Linux and macOS depends on the version of the International Components for Unicode libraries installed on the system. ICU 버전 및 ICU 버전이 구현하는 유니코드 버전에 대한 자세한 내용은 ICU 다운로드를 참조하세요.For information on ICU versions and the Unicode versions that they implement, see Downloading ICU.

그러나 두 문자열의 같음 또는 정렬 순서를 평가할 때 하나의 올바른 결과가 생성되지는 않습니다. 결과는 문자열 비교에 사용되는 기준에 따라 다릅니다.However, evaluating two strings for equality or sort order does not yield a single, correct result; the outcome depends on the criteria used to compare the strings. 특히 서수 문자열 비교나 현재 문화권이나 고정 문화권(영어를 기준으로 로캘을 구분하지 않는 문화권)의 대/소문자 구분 및 정렬 규칙을 기준으로 한 문자열 비교에서는 다른 결과가 생성될 수 있습니다.In particular, string comparisons that are ordinal or that are based on the casing and sorting conventions of the current culture or the invariant culture (a locale-agnostic culture based on the English language) may produce different results.

또한 다른 버전의 .NET을 사용하거나 다른 운영 체제 또는 운영 체제 버전의 .NET을 사용하여 문자열을 비교하면 다른 결과가 반환될 수 있습니다.In addition, string comparisons using different versions of .NET or using .NET on different operating systems or operating system versions may return different results. 자세한 내용은 문자열과 유니코드 표준을 참조하세요.For more information, see Strings and the Unicode Standard.

현재 문화권을 사용하는 문자열 비교String comparisons that use the current culture

문자열 비교 시 현재 문화권의 규칙을 사용하는 한 가기 기준이 포함됩니다.One criterion involves using the conventions of the current culture when comparing strings. 현재 문화권을 기준으로 한 비교에는 스레드의 현재 문화권 또는 로캘이 사용됩니다.Comparisons that are based on the current culture use the thread's current culture or locale. 사용자가 문화권을 설정하지 않으면 문화권은 기본적으로 제어판, 국가별 옵션 창의 설정으로 지정됩니다.If the culture is not set by the user, it defaults to the setting in the Regional Options window in Control Panel. 데이터가 언어적으로 관련되는 경우와 문화권이 구분되는 사용자 조작을 반영하는 경우에는 항상 현재 문화권을 기준으로 한 비교를 사용해야 합니다.You should always use comparisons that are based on the current culture when data is linguistically relevant, and when it reflects culture-sensitive user interaction.

그러나 문화권이 변경되면 .NET의 비교 및 대/소문자 지정 동작도 바뀝니다.However, comparison and casing behavior in .NET changes when the culture changes. 애플리케이션이 개발된 컴퓨터와 다른 문화권을 포함하는 컴퓨터에서 애플리케이션을 실행하거나 실행 스레드가 문화권을 변경할 경우 이 동작이 수행됩니다.This happens when an application executes on a computer that has a different culture than the computer on which the application was developed, or when the executing thread changes its culture. 이 동작은 의도적이지만 대부분 개발자가 이해하기가 분명하지는 않습니다.This behavior is intentional, but it remains non-obvious to many developers. 다음 예제에서는 미국 영어("en-US") 및 스웨덴어("sv-SE") 문화권의 정렬 순서 차이를 보여 줍니다.The following example illustrates differences in sort order between the U.S. English ("en-US") and Swedish ("sv-SE") cultures. 정렬된 문자열 배열에서 단어 "ångström", "Windows" 및 "Visual Studio"가 다른 위치에 나타남을 알 수 있습니다.Note that the words "ångström", "Windows", and "Visual Studio" appear in different positions in the sorted string arrays.

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" };
      Array.Sort(values);
      DisplayArray(values);

      // Change culture to Swedish (Sweden).
      string originalCulture = CultureInfo.CurrentCulture.Name;
      Thread.CurrentThread.CurrentCulture = new CultureInfo("sv-SE");
      Array.Sort(values);
      DisplayArray(values);

      // Restore the original culture.
      Thread.CurrentThread.CurrentCulture = new CultureInfo(originalCulture);
    }
    
    private static void DisplayArray(string[] values)
    {
      Console.WriteLine("Sorting using the {0} culture:",  
                        CultureInfo.CurrentCulture.Name);
      foreach (string value in values)
         Console.WriteLine("   {0}", value);

      Console.WriteLine();
    }
}
// The example displays the following output:
//       Sorting using the en-US culture:
//          able
//          Æble
//          ångström
//          apple
//          Visual Studio
//          Windows
//       
//       Sorting using the sv-SE culture:
//          able
//          Æble
//          apple
//          Windows
//          Visual Studio
//          å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" }
      Array.Sort(values)
      DisplayArray(values)

      ' Change culture to Swedish (Sweden).
      Dim originalCulture As String = CultureInfo.CurrentCulture.Name
      Thread.CurrentThread.CurrentCulture = New CultureInfo("sv-SE")
      Array.Sort(values)
      DisplayArray(values)

      ' Restore the original culture.
      Thread.CurrentThread.CurrentCulture = New CultureInfo(originalCulture)
    End Sub
    
    Private Sub DisplayArray(values() As String)
      Console.WRiteLine("Sorting using the {0} culture:", _ 
                        CultureInfo.CurrentCulture.Name)
      For Each value As String In values
         Console.WriteLine("   {0}", value)
      Next
      Console.WriteLine()   
    End Sub
End Module
' The example displays the following output:
'       Sorting using the en-US culture:
'          able
'          Æble
'          ångström
'          apple
'          Visual Studio
'          Windows
'       
'       Sorting using the sv-SE culture:
'          able
'          Æble
'          apple
'          Windows
'          Visual Studio
'          ångström

현재 문화권을 사용하는 대/소문자를 구분하지 않는 비교는 스레드의 현재 문화권에 지정된 대/소문자를 무시한다는 점을 제외하고 문화권 구분 비교와 같습니다.Case-insensitive comparisons that use the current culture are the same as culture-sensitive comparisons, except that they ignore case as dictated by the thread's current culture. 이 동작은 정렬 순서에서도 나타날 수 있습니다.This behavior may manifest itself in sort orders as well.

현재 문화권 의미 체계를 사용하는 비교는 다음 메서드의 기본값입니다.Comparisons that use current culture semantics are the default for the following methods:

모든 경우에 메서드 호출의 의도를 분명하게 나타내도록 StringComparison 매개 변수를 포함하는 오버로드를 호출하는 것이 좋습니다.In any case, we recommend that you call an overload that has a StringComparison parameter to make the intent of the method call clear.

비언어적인 문자열 데이터가 언어적으로 해석되거나 특정 문화권의 문자열 데이터가 다른 문화권의 규칙을 통해 해석되면 감지하기 어려운 버그와 감지할 수 있는 버그가 발생할 수 있습니다.Subtle and not so subtle bugs can emerge when non-linguistic string data is interpreted linguistically, or when string data from a particular culture is interpreted using the conventions of another culture. 대표적인 예는 Turkish-I 문제입니다.The canonical example is the Turkish-I problem.

미국 영어를 포함한 거의 모든 라틴어 알파벳에서 문자 "i"(\u0069)는 문자 "I"(\u0049)의 소문자 버전입니다.For nearly all Latin alphabets, including U.S. English, the character "i" (\u0069) is the lowercase version of the character "I" (\u0049). 이 대/소문자 구분 규칙은 해당 문화권에서 프로그래밍하는 사용자에게 빠르게 기본 규칙이 되었습니다.This casing rule quickly becomes the default for someone programming in such a culture. 그러나 터키어("tr-TR") 알파벳에는 "i"의 대문자 버전인 "점이 있는 I" 문자 "İ"(\u0130)가 포함됩니다.However, the Turkish ("tr-TR") alphabet includes an "I with a dot" character "İ" (\u0130), which is the capital version of "i". 터키어에는 대문자 버전이 "I"인 "점이 없는 i" 문자 , "ı"(\u0131)도 포함됩니다.Turkish also includes a lowercase "i without a dot" character, "ı" (\u0131), which capitalizes to "I". 이 동작은 아제르바이잔어("az") 문화권에서도 발생합니다.This behavior occurs in the Azerbaijani ("az") culture as well.

따라서 "i"를 대문자로 변환하거나 "I"를 소문자로 변환하는 방법에 대한 가정이 모든 문화권에서 유효한 것은 아닙니다.Therefore, assumptions made about capitalizing "i" or lowercasing "I" are not valid among all cultures. 문자열 비교 루틴에 대해 기본 오버로드를 사용하면 이 오버로드에는 문화권 간의 차이가 적용됩니다.If you use the default overloads for string comparison routines, they will be subject to variance between cultures. 문자열 "file" 및 "FILE"의 대/소문자를 구분하지 않는 비교를 수행하는 다음 시도와 같이, 비교할 데이터가 비언어적일 경우 기본 오버로드를 사용하면 원하지 않는 결과가 생성될 수 있습니다.If the data to be compared is non-linguistic, using the default overloads can produce undesirable results, as the following attempt to perform a case-insensitive comparison of the strings "file" and "FILE" illustrates.

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

public class Example
{
   public static void Main()
   {
      string fileUrl = "file";
      Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US");
      Console.WriteLine("Culture = {0}",
                        Thread.CurrentThread.CurrentCulture.DisplayName);
      Console.WriteLine("(file == FILE) = {0}", 
                       fileUrl.StartsWith("FILE", true, null));
      Console.WriteLine();
      
      Thread.CurrentThread.CurrentCulture = new CultureInfo("tr-TR");
      Console.WriteLine("Culture = {0}",
                        Thread.CurrentThread.CurrentCulture.DisplayName);
      Console.WriteLine("(file == FILE) = {0}", 
                        fileUrl.StartsWith("FILE", true, null));
   }
}
// The example displays the following output:
//       Culture = English (United States)
//       (file == FILE) = True
//       
//       Culture = Turkish (Turkey)
//       (file == FILE) = False
Imports System.Globalization
Imports System.Threading

Module Example
   Public Sub Main()
      Dim fileUrl = "file"
      Thread.CurrentThread.CurrentCulture = New CultureInfo("en-US")
      Console.WriteLine("Culture = {0}", _
                        Thread.CurrentThread.CurrentCulture.DisplayName)
      Console.WriteLine("(file == FILE) = {0}", _ 
                       fileUrl.StartsWith("FILE", True, Nothing))
      Console.WriteLine()
      
      Thread.CurrentThread.CurrentCulture = New CultureInfo("tr-TR")
      Console.WriteLine("Culture = {0}", _
                        Thread.CurrentThread.CurrentCulture.DisplayName)
      Console.WriteLine("(file == FILE) = {0}", _ 
                        fileUrl.StartsWith("FILE", True, Nothing))
   End Sub
End Module
' The example displays the following output:
'       Culture = English (United States)
'       (file == FILE) = True
'       
'       Culture = Turkish (Turkey)
'       (file == FILE) = False

다음 예제와 같이 보안 관련 설정에서 문화권이 의도치 않게 사용되면 이 비교로 인해 큰 문제가 발생할 수 있습니다.This comparison could cause significant problems if the culture is inadvertently used in security-sensitive settings, as in the following example. IsFileURI("file:")와 같은 메서드 호출은 현재 문화권이 미국 영어이면 true를 반환하지만 현재 문화권이 터키어이면 false를 반환합니다.A method call such as IsFileURI("file:") returns true if the current culture is U.S. English, but false if the current culture is Turkish. 따라서 터키어 시스템에서는 누군가 "FILE:"으로 시작하는 대/소문자를 구분하지 않는 URI에 대한 액세스를 차단하는 보안 조치를 회피할 수 있습니다.Thus, on Turkish systems, someone could circumvent security measures that block access to case-insensitive URIs that begin with "FILE:".

public static bool IsFileURI(String path) 
{
   return path.StartsWith("FILE:", true, null);
}
Public Shared Function IsFileURI(path As String) As Boolean 
   Return path.StartsWith("FILE:", True, Nothing)
End Function

이 경우 "file:"은 비언어적, 문화권을 구분하지 않는 식별자로 해석되므로 코드를 다음 예제와 같이 작성해야 합니다.In this case, because "file:" is meant to be interpreted as a non-linguistic, culture-insensitive identifier, the code should instead be written as shown in the following example:

public static bool IsFileURI(string path) 
{
   return path.StartsWith("FILE:", StringComparison.OrdinalIgnoreCase);
}
Public Shared Function IsFileURI(path As String) As Boolean 
    Return path.StartsWith("FILE:", StringComparison.OrdinalIgnoreCase)
End Function

서수 문자열 작업Ordinal string operations

메서드 호출에서 StringComparison.Ordinal 또는 StringComparison.OrdinalIgnoreCase 값을 지정하는 것은 자연어의 특징이 무시되는 비언어적인 비교를 나타냅니다.Specifying the StringComparison.Ordinal or StringComparison.OrdinalIgnoreCase value in a method call signifies a non-linguistic comparison in which the features of natural languages are ignored. 이들 StringComparison 값을 사용하여 호출되는 메서드의 문자열 작업 결정은 문화권별로 매개 변수화되는 대/소문자 구분 또는 동일성 테이블이 아닌 단순 바이트 비교에 기반을 둡니다.Methods that are invoked with these StringComparison values base string operation decisions on simple byte comparisons instead of casing or equivalence tables that are parameterized by culture. 대부분 경우에 이 접근 방법은 의도된 문자열 해석에 가장 적합하지만 코드를 더 빠르고 더 안정적으로 만듭니다.In most cases, this approach best fits the intended interpretation of strings while making code faster and more reliable.

서수 비교는 언어적 해석 없이 각 문자열의 각 바이트가 비교되는 문자열 비교입니다. 예를 들어 "windows"는 "Windows"와 일치하지 않습니다.Ordinal comparisons are string comparisons in which each byte of each string is compared without linguistic interpretation; for example, "windows" does not match "Windows". 이 비교는 기본적으로 C 런타임 strcmp 함수에 대한 호출입니다.This is essentially a call to the C runtime strcmp function. 컨텍스트가 문자열이 정확히 일치해야 함을 나타내거나 보수적인 일치 정책을 요구할 경우 이 비교를 사용합니다.Use this comparison when the context dictates that strings should be matched exactly or demands conservative matching policy. 또한 서수 비교는 결과를 결정할 때 언어 규칙을 적용하지 않으므로 가장 빠른 비교 작업입니다.Additionally, ordinal comparison is the fastest comparison operation because it applies no linguistic rules when determining a result.

.NET의 문자열에는 포함된 null 문자가 있을 수 있습니다.Strings in .NET can contain embedded null characters. 서수 비교와 문화권 구분 비교(고정 문화권을 사용하는 비교 포함) 간 가장 분명한 차이의 하나는 문자열의 포함된 null 문자 처리와 관련됩니다.One of the clearest differences between ordinal and culture-sensitive comparison (including comparisons that use the invariant culture) concerns the handling of embedded null characters in a string. String.CompareString.Equals 메서드를 사용하여 문화권 구분 비교(고정 문화권을 사용하는 비교 포함)를 수행하면 이들 문자가 무시됩니다.These characters are ignored when you use the String.Compare and String.Equals methods to perform culture-sensitive comparisons (including comparisons that use the invariant culture). 따라서 문화권 구분 비교에서 포함된 null 문자가 들어 있는 문자열은 해당 문자가 들어 있지 않은 문자열과 같은 것으로 간주할 수 있습니다.As a result, in culture-sensitive comparisons, strings that contain embedded null characters can be considered equal to strings that do not.

중요

문자열 비교 메서드는 포함된 null 문자를 무시하지만 String.Contains, String.EndsWith, String.IndexOf, String.LastIndexOfString.StartsWith 와 같은 문자열 검색 메서드는 무시하지 않습니다.Although string comparison methods disregard embedded null characters, string search methods such as String.Contains, String.EndsWith, String.IndexOf, String.LastIndexOf, and String.StartsWith do not.

다음 예제에서는 문자열 "Aa" 및 "A"와 "a" 사이에 여러 포함된 null 문자를 포함하는 비슷한 문자열의 문화권 구분 비교를 수행하고 두 문자열을 어떻게 같은 것으로 간주하는지 보여 줍니다.The following example performs a culture-sensitive comparison of the string "Aa" with a similar string that contains several embedded null characters between "A" and "a", and shows how the two strings are considered equal:

using System;

public class Example
{
   public static void Main()
   {
      string str1 = "Aa";
      string str2 = "A" + new String('\u0000', 3) + "a";
      Console.WriteLine("Comparing '{0}' ({1}) and '{2}' ({3}):", 
                        str1, ShowBytes(str1), str2, ShowBytes(str2));
      Console.WriteLine("   With String.Compare:");
      Console.WriteLine("      Current Culture: {0}", 
                        String.Compare(str1, str2, StringComparison.CurrentCulture));
      Console.WriteLine("      Invariant Culture: {0}", 
                        String.Compare(str1, str2, StringComparison.InvariantCulture));

      Console.WriteLine("   With String.Equals:");
      Console.WriteLine("      Current Culture: {0}", 
                        String.Equals(str1, str2, StringComparison.CurrentCulture));
      Console.WriteLine("      Invariant Culture: {0}", 
                        String.Equals(str1, str2, StringComparison.InvariantCulture));
   }
   
   private static string ShowBytes(string str)
   {
      string hexString = String.Empty;
      for (int ctr = 0; ctr < str.Length; ctr++)
      {
         string result = String.Empty;
         result = Convert.ToInt32(str[ctr]).ToString("X4");
         result = " " + result.Substring(0,2) + " " + result.Substring(2, 2);
         hexString += result;
      }
      return hexString.Trim();
   }
}
// The example displays the following output:
//    Comparing 'Aa' (00 41 00 61) and 'A   a' (00 41 00 00 00 00 00 00 00 61):
//       With String.Compare:
//          Current Culture: 0
//          Invariant Culture: 0
//       With String.Equals:
//          Current Culture: True
//          Invariant Culture: True
Module Example
   Public Sub Main()
      Dim str1 As String = "Aa"
      Dim str2 As String = "A" + New String(Convert.ToChar(0), 3) + "a"
      Console.WriteLine("Comparing '{0}' ({1}) and '{2}' ({3}):", _
                        str1, ShowBytes(str1), str2, ShowBytes(str2))
      Console.WriteLine("   With String.Compare:")
      Console.WriteLine("      Current Culture: {0}", _
                        String.Compare(str1, str2, StringComparison.CurrentCulture))
      Console.WriteLine("      Invariant Culture: {0}", _
                        String.Compare(str1, str2, StringComparison.InvariantCulture))

      Console.WriteLine("   With String.Equals:")
      Console.WriteLine("      Current Culture: {0}", _
                        String.Equals(str1, str2, StringComparison.CurrentCulture))
      Console.WriteLine("      Invariant Culture: {0}", _
                        String.Equals(str1, str2, StringComparison.InvariantCulture))
   End Sub
   
   Private Function ShowBytes(str As String) As String
      Dim hexString As String = String.Empty
      For ctr As Integer = 0 To str.Length - 1
         Dim result As String = String.Empty
         result = Convert.ToInt32(str.Chars(ctr)).ToString("X4")
         result = " " + result.Substring(0,2) + " " + result.Substring(2, 2)
         hexString += result
      Next
      Return hexString.Trim()
   End Function
End Module

그러나 다음 예제와 같이 서수 비교를 사용할 경우 문자열을 같은 것으로 간주하지 않습니다.However, the strings are not considered equal when you use ordinal comparison, as the following example shows:

Console.WriteLine("Comparing '{0}' ({1}) and '{2}' ({3}):", 
                  str1, ShowBytes(str1), str2, ShowBytes(str2));
Console.WriteLine("   With String.Compare:");
Console.WriteLine("      Ordinal: {0}", 
                  String.Compare(str1, str2, StringComparison.Ordinal));

Console.WriteLine("   With String.Equals:");
Console.WriteLine("      Ordinal: {0}", 
                  String.Equals(str1, str2, StringComparison.Ordinal));
// The example displays the following output:
//    Comparing 'Aa' (00 41 00 61) and 'A   a' (00 41 00 00 00 00 00 00 00 61):
//       With String.Compare:
//          Ordinal: 97
//       With String.Equals:
//          Ordinal: False
Console.WriteLine("Comparing '{0}' ({1}) and '{2}' ({3}):", _
                  str1, ShowBytes(str1), str2, ShowBytes(str2))
Console.WriteLine("   With String.Compare:")
Console.WriteLine("      Ordinal: {0}", _
                  String.Compare(str1, str2, StringComparison.Ordinal))

Console.WriteLine("   With String.Equals:")
Console.WriteLine("      Ordinal: {0}", _
                  String.Equals(str1, str2, StringComparison.Ordinal))
' The example displays the following output:
'    Comparing 'Aa' (00 41 00 61) and 'A   a' (00 41 00 00 00 00 00 00 00 61):
'       With String.Compare:
'          Ordinal: 97
'       With String.Equals:
'          Ordinal: False

대/소문자를 구분하지 않는 서수 비교는 다음으로 가장 보수적인 접근 방법입니다.Case-insensitive ordinal comparisons are the next most conservative approach. 이들 비교는 대부분 대/소문자 구분을 무시합니다. 예를 들어 "windows"는 "Windows"와 일치합니다.These comparisons ignore most casing; for example, "windows" matches "Windows". ASCII 문자를 처리할 때 이 정책은 사용 가능한 ASCII 대/소문자 구분을 무시한다는 점을 제외하고 StringComparison.Ordinal과 같습니다.When dealing with ASCII characters, this policy is equivalent to StringComparison.Ordinal, except that it ignores the usual ASCII casing. 따라서 [A, Z](\u0041-\u005A)의 모든 문자는 [a,z](\u0061-\007A)의 해당 문자와 일치합니다.Therefore, any character in [A, Z] (\u0041-\u005A) matches the corresponding character in [a,z] (\u0061-\007A). ASCII 범위를 벗어난 대/소문자 구분에는 고정 문화권 테이블이 사용됩니다.Casing outside the ASCII range uses the invariant culture's tables. 따라서 다음 비교는Therefore, the following comparison:

String.Compare(strA, strB, StringComparison.OrdinalIgnoreCase);
String.Compare(strA, strB, StringComparison.OrdinalIgnoreCase)

다음 비교와 같지만 더 빠릅니다.is equivalent to (but faster than) this comparison:

String.Compare(strA.ToUpperInvariant(), strB.ToUpperInvariant(), 
               StringComparison.Ordinal);
String.Compare(strA.ToUpperInvariant(), strB.ToUpperInvariant(), 
               StringComparison.Ordinal)

이들 비교는 매우 빠릅니다.These comparisons are still very fast.

참고

파일 시스템, 레지스트리 키 및 값, 환경 변수의 문자열 동작은 StringComparison.OrdinalIgnoreCase로 가장 잘 표현됩니다.The string behavior of the file system, registry keys and values, and environment variables is best represented by StringComparison.OrdinalIgnoreCase.

StringComparison.OrdinalStringComparison.OrdinalIgnoreCase 는 둘 다 직접 이진 값을 사용하고 일치 항목 찾기에 가장 적합합니다.Both StringComparison.Ordinal and StringComparison.OrdinalIgnoreCase use the binary values directly, and are best suited for matching. 사용 중인 비교 설정을 확신할 수 없으면 다음 두 값의 하나를 사용하세요.When you are not sure about your comparison settings, use one of these two values. 그러나 이들 값은 바이트 단위 비교를 수행하므로 영어 사전처럼 언어 정렬 순서별로 정렬하는 것이 아니라 이진 정렬 순서별로 정렬합니다.However, because they perform a byte-by-byte comparison, they do not sort by a linguistic sort order (like an English dictionary) but by a binary sort order. 사용자에게 표시되는 결과가 대부분 컨텍스트에서 이상하게 표시될 수 있습니다.The results may look odd in most contexts if displayed to users.

서수 의미 체계는 String.Equals 인수(같음 연산자 포함)를 포함하지 않는 StringComparison 오버로드의 기본값입니다.Ordinal semantics are the default for String.Equals overloads that do not include a StringComparison argument (including the equality operator). 모든 경우에 StringComparison 매개 변수를 포함하는 오버로드를 호출하는 것이 좋습니다.In any case, we recommend that you call an overload that has a StringComparison parameter.

고정 문화권을 사용하는 문자열 작업string operations that use the invariant culture

고정 문화권을 사용한 비교에는 정적 CompareInfo 속성에서 반환되는 CultureInfo.InvariantCulture 속성이 사용됩니다.Comparisons with the invariant culture use the CompareInfo property returned by the static CultureInfo.InvariantCulture property. 이 동작은 모든 시스템에서 동일하며, 범위 밖의 모든 문자를 동일한 고정 문화권으로 간주하는 문자로 변환합니다.This behavior is the same on all systems; it translates any characters outside its range into what it believes are equivalent invariant characters. 이 정책은 문화권에 걸쳐 단일 문자열 동작 집합을 유지 관리할 경우 유용하지만 예기치 않은 경과를 제공하기도 합니다.This policy can be useful for maintaining one set of string behavior across cultures, but it often provides unexpected results.

고정 문화권을 사용한 대/소문자를 비교하지 않는 비교에는 비교 정보를 위해 정적 CompareInfo 속성에서 반환되는 CultureInfo.InvariantCulture 속성이 사용됩니다.Case-insensitive comparisons with the invariant culture use the static CompareInfo property returned by the static CultureInfo.InvariantCulture property for comparison information as well. 모든 경우에 변환된 문자 간의 차이는 무시됩니다.Any case differences among these translated characters are ignored.

StringComparison.InvariantCultureStringComparison.Ordinal 을 사용하는 비교는 ASCII 문자열과 똑같이 작동합니다.Comparisons that use StringComparison.InvariantCulture and StringComparison.Ordinal work identically on ASCII strings. 그러나 StringComparison.InvariantCulture 는 바이트 집합으로 해석되어야 하는 문자열에 적절하지 않을 수 있는 언어적 결정을 내립니다.However, StringComparison.InvariantCulture makes linguistic decisions that might not be appropriate for strings that have to be interpreted as a set of bytes. CultureInfo.InvariantCulture.CompareInfo 개체를 사용하면 Compare 메서드가 특정 문자 집합을 같은 것으로 해석합니다.The CultureInfo.InvariantCulture.CompareInfo object makes the Compare method interpret certain sets of characters as equivalent. 예를 들어 다음 동일성은 고정 문화권에서 유효합니다.For example, the following equivalence is valid under the invariant culture:

InvariantCulture: a + ̊ = åInvariantCulture: a + ̊ = å

LATIN SMALL LETTER A 문자 “a”(\u0061)는 COMBINING RING ABOVE 문자 “+ " ̊”(\u030a) 옆에 있을 경우 LATIN SMALL LETTER A WITH RING ABOVE 문자 “å”(\u00e5)로 해석됩니다.The LATIN SMALL LETTER A character "a" (\u0061), when it is next to the COMBINING RING ABOVE character "+ " ̊" (\u030a), is interpreted as the LATIN SMALL LETTER A WITH RING ABOVE character "å" (\u00e5). 다음 예제와 같이 이 동작은 서수 비교와 다릅니다.As the following example shows, this behavior differs from ordinal comparison.

string separated = "\u0061\u030a";
string combined = "\u00e5";
      
Console.WriteLine("Equal sort weight of {0} and {1} using InvariantCulture: {2}",
                  separated, combined, 
                  String.Compare(separated, combined, 
                                 StringComparison.InvariantCulture) == 0);

Console.WriteLine("Equal sort weight of {0} and {1} using Ordinal: {2}",
                  separated, combined,
                  String.Compare(separated, combined, 
                                 StringComparison.Ordinal) == 0);
// The example displays the following output:
//    Equal sort weight of a° and å using InvariantCulture: True
//    Equal sort weight of a° and å using Ordinal: False      
Dim separated As String = ChrW(&h61) + ChrW(&h30a)
Dim combined As String = ChrW(&he5)
      
Console.WriteLine("Equal sort weight of {0} and {1} using InvariantCulture: {2}", _
                  separated, combined, _
                  String.Compare(separated, combined, _ 
                                 StringComparison.InvariantCulture) = 0)

Console.WriteLine("Equal sort weight of {0} and {1} using Ordinal: {2}", _
                  separated, combined, _
                  String.Compare(separated, combined, _
                                 StringComparison.Ordinal) = 0)
' The example displays the following output:
'    Equal sort weight of a° and å using InvariantCulture: True
'    Equal sort weight of a° and å using Ordinal: False

파일 이름, 쿠키 또는 "å"와 같은 조합이 나타날 수 있는 다른 항목을 해석할 때 서수 비교는 가장 투명하고 적합한 동작을 제공합니다.When interpreting file names, cookies, or anything else where a combination such as "å" can appear, ordinal comparisons still offer the most transparent and fitting behavior.

모든 것을 고려해 보면 고정 문화권에는 비교에 유용할 수 있는 속성이 거의 없습니다.On balance, the invariant culture has very few properties that make it useful for comparison. 고정 문화권은 완전한 기호 동일성을 보장하지 못하게 하는 언어 관련 방식으로 비교를 수행하지만 모든 문화권에서 표시하기에 적합하지 않습니다.It does comparison in a linguistically relevant manner, which prevents it from guaranteeing full symbolic equivalence, but it is not the choice for display in any culture. 비교에 StringComparison.InvariantCulture 를 사용하는 몇 가지 이유의 하나는 서로 다른 문화에서 동일하게 표시되도록 순서가 지정된 데이터를 유지하는 것입니다.One of the few reasons to use StringComparison.InvariantCulture for comparison is to persist ordered data for a cross-culturally identical display. 예를 들어 표시하기 위한 정렬된 식별자 목록을 포함하는 큰 데이터 파일이 애플리케이션과 함께 제공될 경우 이 목록에 추가하려면 고정 스타일 정렬을 사용한 삽입이 필요합니다.For example, if a large data file that contains a list of sorted identifiers for display accompanies an application, adding to this list would require an insertion with invariant-style sorting.

메서드 호출을 위한 StringComparison 멤버 선택Choosing a StringComparison member for your method call

다음 표에서는 의미 체계 문자열 컨텍스트에서 StringComparison 열거형 멤버로의 매핑을 간략하게 설명합니다.The following table outlines the mapping from semantic string context to a StringComparison enumeration member:

데이터Data 동작Behavior 해당 System.StringComparisonCorresponding System.StringComparison

value
대/소문자 구분 내부 식별자.Case-sensitive internal identifiers.

XML 및 HTTP와 같은 표준의 대/소문자 구분 식별자.Case-sensitive identifiers in standards such as XML and HTTP.

대/소문자 구분 보안 관련 설정.Case-sensitive security-related settings.
바이트가 정확히 일치하는 비언어적 식별자.A non-linguistic identifier, where bytes match exactly. Ordinal
대/소문자를 구분하지 않는 내부 식별자.Case-insensitive internal identifiers.

XML 및 HTTP와 같은 표준의 대/소문자를 구분하지 않는 식별자.Case-insensitive identifiers in standards such as XML and HTTP.

파일 경로.File paths.

레지스트리 키 및 값.Registry keys and values.

환경 변수.Environment variables.

리소스 식별자(예: 핸들 이름).Resource identifiers (for example, handle names).

대/소문자를 구분하지 않는 보안 관련 설정.Case-insensitive security-related settings.
대/소문자가 불규칙한 비언어적 식별자, 특히 대부분 Windows 시스템 서비스에 저장된 데이터.A non-linguistic identifier, where case is irrelevant; especially data stored in most Windows system services. OrdinalIgnoreCase
일부 지속되는 언어적으로 관련된 데이터.Some persisted, linguistically relevant data.

고정 정렬 순서가 필요한 언어 데이터 표시.Display of linguistic data that requires a fixed sort order.
언어적으로 관련된 문화권을 구분하지 않는 데이터.Culturally agnostic data that still is linguistically relevant. InvariantCulture

또는-or-

InvariantCultureIgnoreCase
사용자에게 표시된 데이터.Data displayed to the user.

대부분 사용자 입력.Most user input.
로컬 언어적 사용자 지정이 필요한 데이터.Data that requires local linguistic customs. CurrentCulture

또는-or-

CurrentCultureIgnoreCase

.NET에서 일반적인 문자열 비교 방법Common string comparison methods in .NET

다음 섹션에서는 문자열 비교에 가장 일반적으로 사용되는 메서드에 대해 설명합니다.The following sections describe the methods that are most commonly used for string comparison.

String.CompareString.Compare

기본 해석: StringComparison.CurrentCulture.Default interpretation: StringComparison.CurrentCulture.

문자열 해석의 가장 중심적인 작업으로, 이들 메서드 호출의 모든 인스턴스를 검사하여 문자열이 현재 문화권에 따라 해석되는지, 아니면 문화권과 관계가 없는지를 결정해야 합니다.As the operation most central to string interpretation, all instances of these method calls should be examined to determine whether strings should be interpreted according to the current culture, or dissociated from the culture (symbolically). 일반적으로 이는 후자이고 StringComparison.Ordinal 비교를 사용해야 합니다.Typically, it is the latter, and a StringComparison.Ordinal comparison should be used instead.

System.Globalization.CompareInfo 속성에서 반환되는 CultureInfo.CompareInfo 클래스에는 Compare 플래그 열거형을 통해 다양한 일치 항목 찾기 옵션(서수, 공백 무시, 가나 형식 무시 등)을 제공하는 CompareOptions 메서드가 포함됩니다.The System.Globalization.CompareInfo class, which is returned by the CultureInfo.CompareInfo property, also includes a Compare method that provides a large number of matching options (ordinal, ignoring white space, ignoring kana type, and so on) by means of the CompareOptions flag enumeration.

String.CompareToString.CompareTo

기본 해석: StringComparison.CurrentCulture.Default interpretation: StringComparison.CurrentCulture.

이 메서드는 현재 StringComparison 형식을 지정하는 오버로드를 제공하지 않습니다.This method does not currently offer an overload that specifies a StringComparison type. 일반적으로 이 메서드를 권장되는 String.Compare(String, String, StringComparison) 양식으로 변환할 수 있습니다.It is usually possible to convert this method to the recommended String.Compare(String, String, StringComparison) form.

IComparableIComparable<T> 인터페이스를 구현하는 형식이 이 메서드를 구현합니다.Types that implement the IComparable and IComparable<T> interfaces implement this method. StringComparison 매개 변수의 옵션을 제공하지 않으므로 형식 구현 시 사용자가 생성자에서 StringComparer를 구현해야 할 수 있습니다.Because it does not offer the option of a StringComparison parameter, implementing types often let the user specify a StringComparer in their constructor. 다음 예제에서는 클래스 생성자에 FileName 매개 변수가 포함된 StringComparer 클래스를 정의합니다.The following example defines a FileName class whose class constructor includes a StringComparer parameter. StringComparer 개체는 FileName.CompareTo 메서드에 사용됩니다.This StringComparer object is then used in the FileName.CompareTo method.

using System;

public class FileName : IComparable
{
   string fname;
   StringComparer comparer; 
   
   public FileName(string name, StringComparer comparer)
   {
      if (String.IsNullOrEmpty(name))
         throw new ArgumentNullException("name");

      this.fname = name;
      
      if (comparer != null)
         this.comparer = comparer;
      else
         this.comparer = StringComparer.OrdinalIgnoreCase;
   }

   public string Name
   {
      get { return fname; }
   }
   
   public int CompareTo(object obj)
   {
      if (obj == null) return 1;

      if (! (obj is FileName))
         return comparer.Compare(this.fname, obj.ToString());
      else
         return comparer.Compare(this.fname, ((FileName) obj).Name);
   }
}
Public Class FileName : Implements IComparable
   Dim fname As String
   Dim comparer As StringComparer 
   
   Public Sub New(name As String, comparer As StringComparer)
      If String.IsNullOrEmpty(name) Then
         Throw New ArgumentNullException("name")
      End If

      Me.fname = name
      
      If comparer IsNot Nothing Then
         Me.comparer = comparer
      Else
         Me.comparer = StringComparer.OrdinalIgnoreCase
      End If      
   End Sub

   Public ReadOnly Property Name As String
      Get
         Return fname
      End Get   
   End Property
   
   Public Function CompareTo(obj As Object) As Integer _
          Implements IComparable.CompareTo
      If obj Is Nothing Then Return 1

      If Not TypeOf obj Is FileName Then
         obj = obj.ToString()
      Else
         obj = CType(obj, FileName).Name
      End If         
      Return comparer.Compare(Me.fname, obj)
   End Function
End Class

String.EqualsString.Equals

기본 해석: StringComparison.Ordinal.Default interpretation: StringComparison.Ordinal.

String 클래스를 통해 정적 또는 인스턴스 Equals 메서드 오버로드를 호출하거나 정적 같음 연산자를 사용하여 같음 여부를 테스트할 수 있습니다.The String class lets you test for equality by calling either the static or instance Equals method overloads, or by using the static equality operator. 오버로드 및 연산자에는 기본적으로 서수 비교가 사용됩니다.The overloads and operator use ordinal comparison by default. 그러나 서수 비교를 수행하려 해도 StringComparison 형식을 명시적으로 지정하는 오버로드를 호출하는 것이 좋습니다. 이렇게 하면 특정 문자열 해석을 위해 코드를 더 쉽게 검색할 수 있습니다.However, we still recommend that you call an overload that explicitly specifies the StringComparison type even if you want to perform an ordinal comparison; this makes it easier to search code for a certain string interpretation.

String.ToUpper 및 String.ToLowerString.ToUpper and String.ToLower

기본 해석: StringComparison.CurrentCulture.Default interpretation: StringComparison.CurrentCulture.

문자열을 대문자 또는 소문자에 적용하는 방법은 대/소문자와 관계없이 문자열 비교 시 작은 정규화로 사용되므로 이들 메서드를 사용할 때 주의해야 합니다.You should be careful when you use these methods, because forcing a string to a uppercase or lowercase is often used as a small normalization for comparing strings regardless of case. 이들 메서드를 사용할 경우 대/소문자를 구분하지 않는 비교를 사용하는 것이 좋습니다.If so, consider using a case-insensitive comparison.

String.ToUpperInvariantString.ToLowerInvariant 메서드도 사용할 수 있습니다.The String.ToUpperInvariant and String.ToLowerInvariant methods are also available. ToUpperInvariant 는 대/소문자를 정규화하는 표준 방법입니다.ToUpperInvariant is the standard way to normalize case. StringComparison.OrdinalIgnoreCase 를 사용한 비교는 동작으로 두 가지 호출(두 문자열 인수에 대한 ToUpperInvariant 호출 및 StringComparison.Ordinal을 사용한 비교 수행)의 컴퍼지션입니다.Comparisons made using StringComparison.OrdinalIgnoreCase are behaviorally the composition of two calls: calling ToUpperInvariant on both string arguments, and doing a comparison using StringComparison.Ordinal.

문화권을 나타내는 CultureInfo 개체를 메서드에 전달하여 특정 문화권에서 대문자 및 소문자로 변환하는 데도 오버로드를 사용할 수 있습니다.Overloads are also available for converting to uppercase and lowercase in a specific culture, by passing a CultureInfo object that represents that culture to the method.

Char.ToUpper 및 Char.ToLowerChar.ToUpper and Char.ToLower

기본 해석: StringComparison.CurrentCulture.Default interpretation: StringComparison.CurrentCulture.

이들 메서드는 이전 섹션에서 설명된 String.ToUpperString.ToLower 메서드와 비슷하게 작동합니다.These methods work similarly to the String.ToUpper and String.ToLower methods described in the previous section.

String.StartsWith 및 String.EndsWithString.StartsWith and String.EndsWith

기본 해석: StringComparison.CurrentCulture.Default interpretation: StringComparison.CurrentCulture.

기본적으로 이들 메서드는 둘 다 문화권 구분 비교를 수행합니다.By default, both of these methods perform a culture-sensitive comparison.

String.IndexOf 및 String.LastIndexOfString.IndexOf and String.LastIndexOf

기본 해석: StringComparison.CurrentCulture.Default interpretation: StringComparison.CurrentCulture.

이들 메서드의 기본 오버로드가 비교를 수행하는 방식에는 일관성이 없습니다.There is a lack of consistency in how the default overloads of these methods perform comparisons. String.IndexOf 매개 변수를 포함하는 모든 String.LastIndexOfChar 메서드는 서수 비교를 수행하지만, String.IndexOf 매개 변수를 포함하는 기본 String.LastIndexOfString 메서드는 문화권 구분 비교를 수행합니다.All String.IndexOf and String.LastIndexOf methods that include a Char parameter perform an ordinal comparison, but the default String.IndexOf and String.LastIndexOf methods that include a String parameter perform a culture-sensitive comparison.

String.IndexOf(String) 또는 String.LastIndexOf(String) 메서드를 호출하고 현재 인스턴스에서 찾을 문자열을 전달할 경우 StringComparison 형식을 명시적으로 지정하는 오버로드를 호출하는 것이 좋습니다.If you call the String.IndexOf(String) or String.LastIndexOf(String) method and pass it a string to locate in the current instance, we recommend that you call an overload that explicitly specifies the StringComparison type. Char 인수를 포함하는 오버로드를 사용하면 StringComparison 형식을 지정할 수 없습니다.The overloads that include a Char argument do not allow you to specify a StringComparison type.

문자열 비교를 간접적으로 수행하는 방법Methods that perform string comparison indirectly

문자열 비교를 중심 작업으로 포함하는 일부 문자열이 아닌 메서드에는 StringComparer 형식이 사용됩니다.Some non-string methods that have string comparison as a central operation use the StringComparer type. StringComparer 클래스에는 포함된 StringComparer 메서드가 다음 형식의 문자열 비교를 수행하는 StringComparer.Compare 인스턴스를 반환하는 정적 속성 6개가 포함됩니다.The StringComparer class includes six static properties that return StringComparer instances whose StringComparer.Compare methods perform the following types of string comparisons:

Array.Sort 및 Array.BinarySearchArray.Sort and Array.BinarySearch

기본 해석: StringComparison.CurrentCulture.Default interpretation: StringComparison.CurrentCulture.

컬렉션에 데이터를 저장하거나 영구 데이터를 파일이나 데이터베이스에서 컬렉션으로 읽을 때 현재 문화권을 전환하면 컬렉션에서 고정이 무효화될 수 있습니다.When you store any data in a collection, or read persisted data from a file or database into a collection, switching the current culture can invalidate the invariants in the collection. Array.BinarySearch 메서드는 검색할 배열의 요소가 이미 정렬되었다고 가정합니다.The Array.BinarySearch method assumes that the elements in the array to be searched are already sorted. 배열에서 문자열 요소를 정렬하려고 Array.Sort 메서드는 String.Compare 메서드를 호출하여 개별 요소의 순서를 지정합니다.To sort any string element in the array, the Array.Sort method calls the String.Compare method to order individual elements. 배열이 정렬된 시간과 콘텐츠가 검색된 시간 사이에 문화권이 변경될 경우 문화권 구분 비교자 사용이 위험할 수 있습니다.Using a culture-sensitive comparer can be dangerous if the culture changes between the time that the array is sorted and its contents are searched. 예를 들어 다음 코드에서 스토리지 및 검색은 Thread.CurrentThread.CurrentCulture 속성에 의해 암시적으로 제공되는 비교자에서 작동합니다.For example, in the following code, storage and retrieval operate on the comparer that is provided implicitly by the Thread.CurrentThread.CurrentCulture property. StoreNamesDoesNameExist에 대한 호출 사이에 문화권이 변경되고 특히 배열 콘텐츠가 두 메서드 호출 사이에 지속되면 이진 검색이 실패할 수 있습니다.If the culture can change between the calls to StoreNames and DoesNameExist, and especially if the array contents are persisted somewhere between the two method calls, the binary search may fail.

// Incorrect.
string []storedNames;

public void StoreNames(string [] names)
{
   int index = 0;
   storedNames = new string[names.Length];

   foreach (string name in names)
   {
      this.storedNames[index++] = name;
   }

   Array.Sort(names); // Line A.
}

public bool DoesNameExist(string name)
{
   return (Array.BinarySearch(this.storedNames, name) >= 0);  // Line B.
}
' Incorrect.
Dim storedNames() As String

Public Sub StoreNames(names() As String)
   Dim index As Integer = 0
   ReDim storedNames(names.Length - 1)
   
   For Each name As String In names
      Me.storedNames(index) = name
      index+= 1
   Next
   
   Array.Sort(names)          ' Line A.
End Sub

Public Function DoesNameExist(name As String) As Boolean
   Return Array.BinarySearch(Me.storedNames, name) >= 0      ' Line B.
End Function

배열을 정렬 및 검색할 때 둘 다 같은 서수(문화권을 구분하지 않는) 비교 메서드를 사용하는 다음 예제에서 권장되는 변형을 보여 줍니다.A recommended variation appears in the following example, which uses the same ordinal (culture-insensitive) comparison method both to sort and to search the array. 변경 코드는 두 예제의 Line ALine B 줄에 반영됩니다.The change code is reflected in the lines labeled Line A and Line B in the two examples.

// Correct.
string []storedNames;

public void StoreNames(string [] names)
{
   int index = 0;
   storedNames = new string[names.Length];

   foreach (string name in names)
   {
      this.storedNames[index++] = name;
   }

   Array.Sort(names, StringComparer.Ordinal);  // Line A.
}

public bool DoesNameExist(string name)
{
   return (Array.BinarySearch(this.storedNames, name, StringComparer.Ordinal) >= 0);  // Line B.
}
' Correct.
Dim storedNames() As String

Public Sub StoreNames(names() As String)
   Dim index As Integer = 0
   ReDim storedNames(names.Length - 1)
   
   For Each name As String In names
      Me.storedNames(index) = name
      index+= 1
   Next
   
   Array.Sort(names, StringComparer.Ordinal)           ' Line A.
End Sub

Public Function DoesNameExist(name As String) As Boolean
   Return Array.BinarySearch(Me.storedNames, name, StringComparer.Ordinal) >= 0      ' Line B.
End Function

이 데이터가 문화권에 걸쳐 지속 및 이동되고 이 데이터를 사용자에게 제공할 때 정렬을 사용할 경우 향상된 사용자 출력을 위해 언어적으로 작동하지만 문화권 변경의 영향을 받지 않는 StringComparison.InvariantCulture를 사용하는 것이 좋을 수 있습니다.If this data is persisted and moved across cultures, and sorting is used to present this data to the user, you might consider using StringComparison.InvariantCulture, which operates linguistically for better user output but is unaffected by changes in culture. 다음 예제에서는 두 가지 이전 예제에서 배열 정렬 및 검색에 고정 문화권을 사용하도록 수정합니다.The following example modifies the two previous examples to use the invariant culture for sorting and searching the array.

// Correct.
string []storedNames;

public void StoreNames(string [] names)
{
   int index = 0;
   storedNames = new string[names.Length];

   foreach (string name in names)
   {
      this.storedNames[index++] = name;
   }

   Array.Sort(names, StringComparer.InvariantCulture);  // Line A.
}

public bool DoesNameExist(string name)
{
   return (Array.BinarySearch(this.storedNames, name, StringComparer.InvariantCulture) >= 0);  // Line B.
}
' Correct.
Dim storedNames() As String

Public Sub StoreNames(names() As String)
   Dim index As Integer = 0
   ReDim storedNames(names.Length - 1)
   
   For Each name As String In names
      Me.storedNames(index) = name
      index+= 1
   Next
   
   Array.Sort(names, StringComparer.InvariantCulture)           ' Line A.
End Sub

Public Function DoesNameExist(name As String) As Boolean
   Return Array.BinarySearch(Me.storedNames, name, StringComparer.InvariantCulture) >= 0      ' Line B.
End Function

컬렉션 예제: 해시 가능한 생성자Collections example: Hashtable constructor

문자열 비교 방법이 영향을 미치는 작업의 두 번째 예로는 문자열 해시가 있습니다.Hashing strings provides a second example of an operation that is affected by the way in which strings are compared.

다음 예제에서는 Hashtable 속성에서 반환되는 StringComparer 개체를 전달하여 StringComparer.OrdinalIgnoreCase 개체를 인스턴스화합니다.The following example instantiates a Hashtable object by passing it the StringComparer object that is returned by the StringComparer.OrdinalIgnoreCase property. StringComparer 에서 파생된 StringComparer 클래스는 IEqualityComparer 인터페이스를 구현하므로 해당 GetHashCode 메서드는 해시 테이블에서 문자열의 해시 코드를 컴퓨팅하는 데 사용됩니다.Because a class StringComparer that is derived from StringComparer implements the IEqualityComparer interface, its GetHashCode method is used to compute the hash code of strings in the hash table.

const int initialTableCapacity = 100;
Hashtable h;

public void PopulateFileTable(string directory)
{
   h = new Hashtable(initialTableCapacity, 
                     StringComparer.OrdinalIgnoreCase);
         
   foreach (string file in Directory.GetFiles(directory))
         h.Add(file, File.GetCreationTime(file));
}

public void PrintCreationTime(string targetFile)
{
   Object dt = h[targetFile];
   if (dt != null)
   {
      Console.WriteLine("File {0} was created at time {1}.",
         targetFile, 
         (DateTime) dt);
   }
   else
   {
      Console.WriteLine("File {0} does not exist.", targetFile);
   }
}
Const initialTableCapacity As Integer = 100
Dim h As Hashtable

Public Sub PopulateFileTable(dir As String)
   h = New Hashtable(initialTableCapacity, _
                     StringComparer.OrdinalIgnoreCase)
                     
   For Each filename As String In Directory.GetFiles(dir)
      h.Add(filename, File.GetCreationTime(filename))
   Next                        
End Sub

Public Sub PrintCreationTime(targetFile As String)
   Dim dt As Object = h(targetFile)
   If dt IsNot Nothing Then
      Console.WriteLine("File {0} was created at {1}.", _
         targetFile, _
         CDate(dt))
   Else
      Console.WriteLine("File {0} does not exist.", targetFile)
   End If
End Sub  

서식이 지정된 데이터 표시 및 유지Displaying and persisting formatted data

숫자와 날짜 및 시간과 같은 문자열이 아닌 데이터를 사용자에게 표시할 때 사용자의 문화권 설정을 사용하여 형식을 지정합니다.When you display non-string data such as numbers and dates and times to users, format them by using the user's cultural settings. 기본적으로 다음 항목은 모두 서식 지정 작업에서 현재 스레드 문화권을 사용합니다.By default, the following all use the current thread culture in formatting operations:

  • C#Visual Basic 컴파일러에서 지원하는 보간된 문자열입니다.Interpolated strings supported by the C# and Visual Basic compilers.
  • C# 또는 Visual Basic 연결 연산자를 사용하거나 직접 String.Concat 메서드를 호출하는 문자열 연결 연산자입니다.String concatenation operations that use the C# or Visual Basic concatenation operators or that call the String.Concat method directly.
  • String.Format 메서드The String.Format method.
  • 숫자 형식과 날짜 및 시간 형식의 ToString 메서드.The ToString methods of the numeric types and the date and time types.

지정된 문화권의 규칙 또는 고정 문화권을 사용하여 문자열의 서식을 지정해야 함을 명시적으로 지정하려면 다음을 수행합니다.To explicitly specify that a string should be formatted by using the conventions of a designated culture or the invariant culture, you can do the following:

  • String.FormatToString 메서드를 사용하는 경우 String.Format(IFormatProvider, String, Object[]) 또는 DateTime.ToString(IFormatProvider)과 같이 provider 매개 변수가 있는 오버로드를 호출하고 CultureInfo.CurrentCulture 속성, 원하는 문화권을 나타내는 CultureInfo 인스턴스 또는 CultureInfo.InvariantCulture 속성을 전달합니다.When using the String.Format and ToString methods, call an overload that has a provider parameter, such as String.Format(IFormatProvider, String, Object[]) or DateTime.ToString(IFormatProvider), and pass it the CultureInfo.CurrentCulture property, a CultureInfo instance that represents the desired culture, or the CultureInfo.InvariantCulture property.

  • 문자열 연결의 경우 컴파일러에서 암시적 변환을 수행하지 못하게 합니다.For string concatenation, do not allow the compiler to perform any implicit conversions. 대신 provider 매개 변수가 있는 ToString 오버로드를 호출하여 명시적 변환을 수행합니다.Instead, perform an explicit conversion by calling a ToString overload that has a provider parameter. 예를 들어 컴파일러는 Double 값을 다음 C# 코드의 문자열로 변환할 때 암시적으로 현재 문화권을 사용합니다.For example, the compiler implicitly uses the current culture when converting a Double value to a string in the following C# code:

    string concat1 = "The amount is " + 126.03 + ".";
    Console.WriteLine(concat1);
    

    대신, 다음 C# 코드와 같이 Double.ToString(IFormatProvider) 메서드를 호출하여 변환에 사용되는 서식 지정 규칙을 사용하는 문화권을 명시적으로 지정할 수 있습니다.Instead, you can explicitly specify the culture whose formatting conventions are used in the conversion by calling the Double.ToString(IFormatProvider) method, as the following C# code does:

    string concat2 = "The amount is " + 126.03.ToString(CultureInfo.InvariantCulture) + ".";
    Console.WriteLine(concat2);
    
  • 문자열 보간의 경우, 보간된 문자열을 String 인스턴스에 할당하는 대신 FormattableString에 할당합니다.For string interpolation, rather than assigning an interpolated string to a String instance, assign it to a FormattableString. 그런 다음, 해당 FormattableString.ToString() 메서드를 호출하여 현재 문화권의 규칙을 반영하는 결과 문자열을 생성하거나 FormattableString.ToString(IFormatProvider) 메서드를 호출하여 지정된 문화권의 규칙을 반영하는 결과 문자열을 생성할 수 있습니다.You can then call its FormattableString.ToString() method produce a result string that reflects the conventions of the current culture, or you can call the FormattableString.ToString(IFormatProvider) method to produce a result string that reflects the conventions of a specified culture. 서식 지정 가능 문자열을 정적 FormattableString.Invariant 메서드에 전달하여 고정 문화권의 규칙을 반영하는 결과 문자열을 생성할 수도 있습니다.You can also pass the formattable string to the static FormattableString.Invariant method to produce a result string that reflects the conventions of the invariant culture. 다음 예제에서 이 방법을 보여 줍니다.The following example illustrates this approach. (이 예제의 출력에는 en-US의 현재 문화권이 반영됩니다.)(The output from the example reflects a current culture of en-US.)

    using System;
    using System.Globalization;
    
    class Program
    {
        static void Main()
        {
            Decimal value = 126.03m;
            FormattableString amount = $"The amount is {value:C}"; 
            Console.WriteLine(amount.ToString());
            Console.WriteLine(amount.ToString(new CultureInfo("fr-FR")));
            Console.WriteLine(FormattableString.Invariant(amount));
        }
    }
    // The example displays the following output:
    //    The amount is $126.03
    //    The amount is 126,03 €
    //    The amount is ¤126.03
    
    Imports System.Globalization
    
    Module Program
        Sub Main()
            Dim value As Decimal = 126.03
            Dim amount As FormattableString = $"The amount is {value:C}" 
            Console.WriteLine(amount.ToString())
            Console.WriteLine(amount.ToString(new CultureInfo("fr-FR")))
            Console.WriteLine(FormattableString.Invariant(amount))
        End Sub
    End Module
    ' The example displays the following output:
    '    The amount is $126.03
    '    The amount is 126,03 €
    '    The amount is ¤126.03
    

문자열이 아닌 데이터를 이진 데이터 또는 형식이 지정된 데이터로 유지할 수 있습니다.You can persist non-string data either as binary data or as formatted data. 서식이 지정된 데이터로 저장하는 경우 provider 매개 변수를 포함하는 서식 지정 메서드 오버로드를 호출하고 CultureInfo.InvariantCulture 속성에 전달해야 합니다.If you choose to save it as formatted data, you should call a formatting method overload that includes a provider parameter and pass it the CultureInfo.InvariantCulture property. 고정 문화권은 문화권 및 컴퓨터와 관계없는 형식이 지정된 데이터에 대해 일관된 형식을 제공합니다.The invariant culture provides a consistent format for formatted data that is independent of culture and machine. 반대로 고정 문화권이 아닌 문화권을 사용하여 형식이 지정된 영구 데이터에는 많은 제한 사항이 있습니다.In contrast, persisting data that is formatted by using cultures other than the invariant culture has a number of limitations:

  • 다른 문화권이 포함된 시스템에서 데이터를 검색하거나 현재 시스템의 사용자가 현재 문화권을 변경하고 데이터를 검색하려고 하면 데이터를 사용하지 못할 수 있습니다.The data is likely to be unusable if it is retrieved on a system that has a different culture, or if the user of the current system changes the current culture and tries to retrieve the data.
  • 특정 컴퓨터의 문화권 속성은 표준 값과 다를 수 있습니다.The properties of a culture on a specific computer can differ from standard values. 언제든지 사용자가 문화권 구분 표시 설정을 사용자 지정할 수 있습니다.At any time, a user can customize culture-sensitive display settings. 이로 인해 사용자가 문화권 설정을 사용자 지정한 후에는 시스템에 저장된 형식이 지정된 데이터를 읽지 못할 수 있습니다.Because of this, formatted data that is saved on a system may not be readable after the user customizes cultural settings. 컴퓨터 간에 형식이 지정된 데이터의 이식성은 훨씬 더 제한적일 수 있습니다.The portability of formatted data across computers is likely to be even more limited.
  • 숫자 또는 날짜/시간의 형식 지정을 관리하는 국제, 지역 또는 국가 표준은 시간에 지나면서 변경되고 이들 변경은 Windows 운영 체제 업데이트에 통합됩니다.International, regional, or national standards that govern the formatting of numbers or dates and times change over time, and these changes are incorporated into Windows operating system updates. 형식 지정 규칙이 변경될 때 이전 규칙을 사용하여 형식이 지정된 데이터를 읽지 못하게 될 수 있습니다.When formatting conventions change, data that was formatted by using the previous conventions may become unreadable.

다음 예제에서는 문화권 구분 형식 지정을 사용하여 데이터를 유지함으로 인해 제한된 이식성을 보여 줍니다.The following example illustrates the limited portability that results from using culture-sensitive formatting to persist data. 예제에서는 날짜 및 시간 값 배열을 파일에 저장합니다.The example saves an array of date and time values to a file. 이들 값은 영어(미국) 문화권의 규칙을 사용하여 형식이 지정됩니다.These are formatted by using the conventions of the English (United States) culture. 애플리케이션이 현재 스레드 문화권을 프랑스어(스위스)로 변경하고 나면 현재 문화권의 형식 지정 규칙을 사용하여 저장된 값을 읽으려고 합니다.After the application changes the current thread culture to French (Switzerland), it tries to read the saved values by using the formatting conventions of the current culture. 두 데이터 항목을 읽으려는 시도로 인해 FormatException 예외가 throw되고 날짜 배열에는 MinValue와 같은 잘못된 두 가지 요소가 포함됩니다.The attempt to read two of the data items throws a FormatException exception, and the array of dates now contains two incorrect elements that are equal to MinValue.

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

public class Example
{
   private static string filename = @".\dates.dat";

   public static void Main()
   {
      DateTime[] dates = { new DateTime(1758, 5, 6, 21, 26, 0), 
                           new DateTime(1818, 5, 5, 7, 19, 0), 
                           new DateTime(1870, 4, 22, 23, 54, 0),  
                           new DateTime(1890, 9, 8, 6, 47, 0), 
                           new DateTime(1905, 2, 18, 15, 12, 0) }; 
      // Write the data to a file using the current culture.
      WriteData(dates);
      // Change the current culture.
      Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("fr-CH");
      // Read the data using the current culture.
      DateTime[] newDates = ReadData();
      foreach (var newDate in newDates)
         Console.WriteLine(newDate.ToString("g"));
   }
   
   private static void WriteData(DateTime[] dates) 
   {
      StreamWriter sw = new StreamWriter(filename, false, Encoding.UTF8);    
      for (int ctr = 0; ctr < dates.Length; ctr++) {
         sw.Write("{0}", dates[ctr].ToString("g", CultureInfo.CurrentCulture));
         if (ctr < dates.Length - 1) sw.Write("|");   
      }      
      sw.Close();
   }
   
   private static DateTime[] ReadData() 
   {
      bool exceptionOccurred = false;
           
      // Read file contents as a single string, then split it.
      StreamReader sr = new StreamReader(filename, Encoding.UTF8);
      string output = sr.ReadToEnd();
      sr.Close();   

      string[] values = output.Split( new char[] { '|' } );
      DateTime[] newDates = new DateTime[values.Length]; 
      for (int ctr = 0; ctr < values.Length; ctr++) {
         try {
            newDates[ctr] = DateTime.Parse(values[ctr], CultureInfo.CurrentCulture);
         }
         catch (FormatException) {
            Console.WriteLine("Failed to parse {0}", values[ctr]);
            exceptionOccurred = true;
         }
      }      
      if (exceptionOccurred) Console.WriteLine();
      return newDates;
   }
}
// The example displays the following output:
//       Failed to parse 4/22/1870 11:54 PM
//       Failed to parse 2/18/1905 3:12 PM
//       
//       05.06.1758 21:26
//       05.05.1818 07:19
//       01.01.0001 00:00
//       09.08.1890 06:47
//       01.01.0001 00:00
//       01.01.0001 00:00
Imports System.Globalization
Imports System.IO
Imports System.Text
Imports System.Threading

Module Example
   Private filename As String = ".\dates.dat"
   
   Public Sub Main()
      Dim dates() As Date = { #5/6/1758 9:26PM#, #5/5/1818 7:19AM#, _ 
                              #4/22/1870 11:54PM#, #9/8/1890 6:47AM#, _ 
                              #2/18/1905 3:12PM# }
      ' Write the data to a file using the current culture.
      WriteData(dates)
      ' Change the current culture.
      Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("fr-CH")
      ' Read the data using the current culture.
      Dim newDates() As Date = ReadData()
      For Each newDate In newDates
         Console.WriteLine(newDate.ToString("g"))
      Next
   End Sub
   
   Private Sub WriteData(dates() As Date)
      Dim sw As New StreamWriter(filename, False, Encoding.Utf8)    
      For ctr As Integer = 0 To dates.Length - 1
         sw.Write("{0}", dates(ctr).ToString("g", CultureInfo.CurrentCulture))
         If ctr < dates.Length - 1 Then sw.Write("|")   
      Next      
      sw.Close()
   End Sub
   
   Private Function ReadData() As Date()
      Dim exceptionOccurred As Boolean = False
           
      ' Read file contents as a single string, then split it.
      Dim sr As New StreamReader(filename, Encoding.Utf8)
      Dim output As String = sr.ReadToEnd()
      sr.Close()   

      Dim values() As String = output.Split( {"|"c } )
      Dim newDates(values.Length - 1) As Date 
      For ctr As Integer = 0 To values.Length - 1
         Try
            newDates(ctr) = DateTime.Parse(values(ctr), CultureInfo.CurrentCulture)
         Catch e As FormatException
            Console.WriteLine("Failed to parse {0}", values(ctr))
            exceptionOccurred = True
         End Try
      Next      
      If exceptionOccurred Then Console.WriteLine()
      Return newDates
   End Function
End Module
' The example displays the following output:
'       Failed to parse 4/22/1870 11:54 PM
'       Failed to parse 2/18/1905 3:12 PM
'       
'       05.06.1758 21:26
'       05.05.1818 07:19
'       01.01.0001 00:00
'       09.08.1890 06:47
'       01.01.0001 00:00
'       01.01.0001 00:00
'

그러나 CultureInfo.CurrentCultureCultureInfo.InvariantCulture 에 대한 호출에서 DateTime.ToString(String, IFormatProvider) 속성을 DateTime.Parse(String, IFormatProvider)로 바꾸면 다음 출력과 같이 영구 날짜 및 시간 데이터가 성공적으로 복원됩니다.However, if you replace the CultureInfo.CurrentCulture property with CultureInfo.InvariantCulture in the calls to DateTime.ToString(String, IFormatProvider) and DateTime.Parse(String, IFormatProvider), the persisted date and time data is successfully restored, as the following output shows:

06.05.1758 21:26
05.05.1818 07:19
22.04.1870 23:54
08.09.1890 06:47
18.02.1905 15:12

참고 항목See also