Выполнение строковых операций без учета языка и региональных параметров в коллекциях

В пространстве имен System.Collections существуют классы и члены, поведение которых по умолчанию зависит от языка и региональных параметров. Конструкторы без параметров для классов CaseInsensitiveComparer и CaseInsensitiveHashCodeProvider инициализируют новый экземпляр с помощью свойства Thread.CurrentCulture. Все перегрузки метода CollectionsUtil.CreateCaseInsensitiveHashtable создают новый экземпляр класса Hashtable, по умолчанию используя свойство Thread.CurrentCulture. Перегруженные версии метода ArrayList.Sort по умолчанию выполняют сортировку с учетом языка и региональных параметров, используя свойства Thread.CurrentCulture. Если в качестве ключей используются строки, на сортировку и поиск по SortedList влияет значение Thread.CurrentCulture. Для получения результатов, не зависящих от языка и региональных параметров, для этих классов и методов в пространстве имен Collections следуйте рекомендациям, приведенным в этом разделе.

Примечание.

Если передать CultureInfo.InvariantCulture в метод сравнения, сравнение выполняется без учета языка и региональных параметров. Однако при этом не выполняется нелингвистическое сравнение, например для путей к файлам, разделов реестра и переменных среды. Также не поддерживается принятие решений по безопасности на основе результата сравнения. Для нелингвистического сравнения и (или) поддержки принятия решений по безопасности в приложении следует использовать метод сравнения, который принимает значение StringComparison. Приложение должно передавать StringComparison.

Использование классов CaseInsensitiveComparer и CaseInsensitiveHashCodeProvider

В конструкторах без параметров для CaseInsensitiveHashCodeProvider и CaseInsensitiveComparer инициализируется новый экземпляр класса с использованием Thread.CurrentCulture. Это приводит к тому, что язык и региональные параметры учитываются при сравнении. В следующем примере кода показан конструктор для Hashtable, который учитывает язык и региональные параметры, так как он использует конструкторы без параметров для CaseInsensitiveHashCodeProvider и CaseInsensitiveComparer.

internalHashtable = New Hashtable(CaseInsensitiveHashCodeProvider.Default, CaseInsensitiveComparer.Default)
internalHashtable = new Hashtable(CaseInsensitiveHashCodeProvider.Default, CaseInsensitiveComparer.Default);

Если вы хотите создать Hashtable, не учитывающий язык и региональные параметры, с помощью классов CaseInsensitiveComparer и CaseInsensitiveHashCodeProvider, инициализируйте новые экземпляры этих классов с помощью конструкторов, которые принимают параметр culture. В качестве параметра culture укажите CultureInfo.InvariantCulture. В следующем примере кода показан конструктор для Hashtable, который не учитывает язык и региональные параметры.

internalHashtable = New Hashtable(New
    CaseInsensitiveHashCodeProvider(CultureInfo.InvariantCulture),
    New CaseInsensitiveComparer(CultureInfo.InvariantCulture))
internalHashtable = new Hashtable(new CaseInsensitiveHashCodeProvider
    (CultureInfo.InvariantCulture),
    new CaseInsensitiveComparer(CultureInfo.InvariantCulture));

Использование метода CollectionsUtil.CreateCaseInsensitiveHashTable

Для создания нового экземпляра класса Hashtable, который не учитывает регистр строк, удобно использовать метод CollectionsUtil.CreateCaseInsensitiveHashTable. Однако все перегруженные версии метода CollectionsUtil.CreateCaseInsensitiveHashTable учитывают язык и региональные параметры, так как они используют свойство Thread.CurrentCulture. С помощью этого метода нельзя создать Hashtable, который не учитывает язык и региональные параметры. Чтобы создать Hashtable, который не учитывает язык и региональные параметры, используйте конструктор Hashtable, который принимает параметр culture. В качестве параметра culture укажите CultureInfo.InvariantCulture. В следующем примере кода показан конструктор для Hashtable, который не учитывает язык и региональные параметры.

internalHashtable = New Hashtable(New
    CaseInsensitiveHashCodeProvider(CultureInfo.InvariantCulture),
    New CaseInsensitiveComparer(CultureInfo.InvariantCulture))
internalHashtable = new Hashtable(new CaseInsensitiveHashCodeProvider
    (CultureInfo.InvariantCulture),
    new CaseInsensitiveComparer(CultureInfo.InvariantCulture));

Использование класса SortedList

SortedList представляет коллекцию пар "ключ — значение", упорядоченных по ключу. Обращаться к парам можно по ключу и индексу. Если используется SortedList и в качестве ключей используются строки, на поиск и сортировку может повлиять свойство Thread.CurrentCulture. Чтобы SortedList не учитывал язык и региональные параметры, создайте SortedList с помощью одного из конструкторов, принимающих параметр comparer. Параметр comparer указывает реализацию IComparer, которую нужно использовать при сравнении ключей. Для сравнения ключей в качестве параметра укажите пользовательский класс сравнения, который использует CultureInfo.InvariantCulture. В следующем примере показан пользовательский класс сравнения, не учитывающий язык и региональные параметры. Для этого в конструктор SortedList передается параметр comparer.

Imports System.Collections
Imports System.Globalization

Friend Class InvariantComparer
    Implements IComparer
    Private m_compareInfo As CompareInfo
    Friend Shared [Default] As New InvariantComparer()

    Friend Sub New()
        m_compareInfo = CultureInfo.InvariantCulture.CompareInfo
    End Sub

    Public Function Compare(a As Object, b As Object) As Integer _
            Implements IComparer.Compare
        Dim sa As String = CType(a, String)
        Dim sb As String = CType(b, String)
        If Not (sa Is Nothing) And Not (sb Is Nothing) Then
            Return m_compareInfo.Compare(sa, sb)
        Else
            Return Comparer.Default.Compare(a, b)
        End If
    End Function
End Class
using System;
using System.Collections;
using System.Globalization;

internal class InvariantComparer : IComparer
{
    private CompareInfo _compareInfo;
    internal static readonly InvariantComparer Default = new
        InvariantComparer();

    internal InvariantComparer()
    {
        _compareInfo = CultureInfo.InvariantCulture.CompareInfo;
    }

    public int Compare(Object a, Object b)
    {
        if (a is string sa && b is string sb)
            return _compareInfo.Compare(sa, sb);
        else
            return Comparer.Default.Compare(a,b);
    }
}

В общем случае при использовании SortedList для строк без указания пользовательского инвариантного класса сравнения изменение Thread.CurrentCulture после заполнения списка может сделать список недействительным.

Использование метода ArrayList.Sort

Перегруженные версии метода по умолчанию ArrayList.Sort выполняют сортировку с учетом языка и региональных параметров благодаря использованию свойства Thread.CurrentCulture. Результаты могут различаться из-за различного порядка сортировки в разных языках и региональных параметрах. Чтобы результат не зависел от языка и региональных параметров, используйте перегрузки этого метода, которые принимают реализацию IComparer. В качестве параметра comparer укажите пользовательский инвариантный класс сравнения, который использует CultureInfo.InvariantCulture. Пример пользовательского инвариантного класса сравнения приведен в разделе Использование класса SortedList.

См. также