Elegant way of converting between StringComparison and StringComparer?

扶醉桌前 提交于 2019-12-19 16:54:11

问题


Some .NET methods use StringComparison as parameter, some use StringComparer (often in form of IComparer). The difference is clear. Is there some elegant way how to get StringComparison from StringComparer or vice versa?

I can always write simple method which uses Case statement, but perhaps there is already something present in .NET what I am overlooking.


回答1:


Going from StringComparison to StringComparer is simple - just create a Dictionary<StringComparison, StringComparer>:

var map = new Dictionary<StringComparison, StringComparer>
{
    { StringComparison.Ordinal, StringComparer.Ordinal },
    // etc
};

There is a StringComparer for every StringComparison value, so that way works really easily. Mind you, StringComparer.CurrentCulture depends on the current thread culture - so if you populate the dictionary and then modify the thread's culture (or do it from a different thread with a different culture) you may end up with the wrong value. You potentially want a Dictionary<StringComparison, Func<StringComparer>>:

var map = new Dictionary<StringComparison, Func<StringComparer>>
{
    { StringComparison.Ordinal, () => StringComparer.Ordinal },
    // etc
};

Then you can get a comparer at any time by invoking the delegate:

var comparer = map[comparison]();

Going the other way is infeasible, because not every StringComparer has a suitable StringComparison. For example, suppose I (in the UK) create a StringComparer for French (StringComparer.Create(new CultureInfo(..., true)). Which StringComparison does that represent? It's not correct for the current culture, the invariant culture, or ordinal comparisons.




回答2:


There isn't something out of the box, but you can create a simple mapping yourself between the comparsion and the comparer:

Dictionary<StringComparison, StringComparer> comparsionToComparer = 
                        new Dictionary<StringComparison, System.StringComparer>
{
    { StringComparison.CurrentCulture, StringComparer.CurrentCulture },
    { StringComparison.CurrentCultureIgnoreCase, StringComparer.CurrentCultureIgnoreCase },
    { StringComparison.InvariantCulture, StringComparer.InvariantCulture },
    { StringComparison.InvariantCultureIgnoreCase, StringComparer.InvariantCultureIgnoreCase },
    { StringComparison.Ordinal, StringComparer.Ordinal },
    { StringComparison.OrdinalIgnoreCase, StringComparer.OrdinalIgnoreCase }
}

And when-ever you need the proper comparer:

var invariantComparer = comparsionToComparer[StringComparsion.InvariantCulture];

Edit:

With C#-6 Dictionary Initializer syntax:

Dictionary<StringComparison, StringComparer> comparsionToComparer = 
                            new Dictionary<StringComparison, System.StringComparer>
{
    [StringComparison.CurrentCulture] = StringComparer.CurrentCulture,
    [StringComparison.CurrentCultureIgnoreCase] = StringComparer.CurrentCultureIgnoreCase,
    [StringComparison.InvariantCulture] = StringComparer.InvariantCulture,
    [StringComparison.InvariantCultureIgnoreCase] = StringComparer.InvariantCultureIgnoreCase,
    [StringComparison.Ordinal] = StringComparer.Ordinal,
    [StringComparison.OrdinalIgnoreCase] = StringComparer.OrdinalIgnoreCase
};

Also, Jons answer refers to the issue of the threads current-culture, which i discarded and should probably be taken into account




回答3:


vb.net version based on accepted answer (and Option Infer Off):

Dim map As New Dictionary(Of StringComparison, Func(Of StringComparer))() _
    From {
        {StringComparison.CurrentCulture, Function() StringComparer.CurrentCulture},
        {StringComparison.CurrentCultureIgnoreCase, Function() StringComparer.CurrentCultureIgnoreCase},
        {StringComparison.InvariantCulture, Function() StringComparer.InvariantCulture},
        {StringComparison.InvariantCultureIgnoreCase, Function() StringComparer.InvariantCultureIgnoreCase},
        {StringComparison.Ordinal, Function() StringComparer.Ordinal},
        {StringComparison.OrdinalIgnoreCase, Function() StringComparer.OrdinalIgnoreCase}
    }

Usage:

Dim comparer As StringComparer = map(comparison)()



回答4:


An a complete extension method for any one who needs quick copy+paste:

public static class StringComparisonExtensions
{
  // from http://stackoverflow.com/a/32764112/548304
  private static readonly Dictionary<StringComparison, Func<StringComparer>> ComparsionToComparer =
    new Dictionary<StringComparison, Func<StringComparer>>
      {
        [StringComparison.CurrentCulture] = () => StringComparer.CurrentCulture,
        [StringComparison.CurrentCultureIgnoreCase] = () => StringComparer.CurrentCultureIgnoreCase,
        [StringComparison.InvariantCulture] = () => StringComparer.InvariantCulture,
        [StringComparison.InvariantCultureIgnoreCase] = () => StringComparer.InvariantCultureIgnoreCase,
        [StringComparison.Ordinal] = () => StringComparer.Ordinal,
        [StringComparison.OrdinalIgnoreCase] = () => StringComparer.OrdinalIgnoreCase
      };

  /// <summary>
  ///  Retrieves a string comparer for the given StringComparison.
  /// </summary>
  public static StringComparer ToComparer(this StringComparison comparison)
  {
    return ComparsionToComparer.GetValueOrDefault(comparison)?.Invoke();
  }
}



回答5:


    public static StringComparer ToComparer(this StringComparison comparison)
    {
        switch (comparison) {
            case StringComparison.CurrentCulture:
                return StringComparer.CurrentCulture;
            case StringComparison.CurrentCultureIgnoreCase:
                return StringComparer.CurrentCultureIgnoreCase;
            case StringComparison.InvariantCulture:
                return StringComparer.InvariantCulture;
            case StringComparison.InvariantCultureIgnoreCase:
                return StringComparer.InvariantCultureIgnoreCase;
            case StringComparison.Ordinal:
                return StringComparer.Ordinal;
            case StringComparison.OrdinalIgnoreCase:
                return StringComparer.OrdinalIgnoreCase;
            default:
                break;
        }

        throw new NotImplementedException("Unknown StringComparison");
    }


来源:https://stackoverflow.com/questions/32763927/elegant-way-of-converting-between-stringcomparison-and-stringcomparer

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!