关于c#:通用字典的不区分大小写的访问

Case insensitive access for generic dictionary

我有一个使用托管DLL的应用程序。其中一个DLL返回一个通用字典:

1
Dictionary<string, int> MyDictionary;

字典包含大小写的键。

另一方面,我得到了一个潜在密钥(字符串)的列表,但是我不能保证这个情况。我正试图用这些键在字典中获取值。但当然,由于我的案例不匹配,以下内容将失败:

1
bool Success = MyDictionary.TryGetValue( MyIndex, out TheValue );

我希望TryGetValue有一个类似于msdn文档中提到的忽略大小写标志,但这似乎对一般字典无效。

有没有一种方法可以忽略键大小写来获取字典的值?是否有比使用正确的StringComparer.ordinalAlignoreCase参数创建字典的新副本更好的解决方案?


在您试图获取值的时候,没有办法指定一个StringComparer。如果您考虑一下,"foo".GetHashCode()"foo".GetHashCode()完全不同,因此没有合理的方法可以在区分大小写的哈希图上实现不区分大小写的get。

但是,您可以首先使用以下命令创建不区分大小写的字典:

1
2
var comparer = StringComparer.OrdinalIgnoreCase;
var caseInsensitiveDictionary = new Dictionary<string, int>(comparer);

或者使用现有区分大小写字典的内容创建一个新的不区分大小写字典(如果您确定没有大小写冲突):-

1
2
3
var oldDictionary = ...;
var comparer = StringComparer.OrdinalIgnoreCase;
var newDictionary = new Dictionary<string, int>(oldDictionary, comparer);

然后,这个新字典在StringComparer.OrdinalIgnoreCase上使用GetHashCode()实现,所以comparer.GetHashCode("foo")comparer.GetHashCode("foo")给您相同的值。

或者,如果字典中只有几个元素,并且/或者您只需要查找一次或两次,则可以将原始字典视为一个IEnumerable>,并对其进行迭代:

1
2
3
4
var myKey = ...;
var myDictionary = ...;
var comparer = StringComparer.OrdinalIgnoreCase;
var value = myDictionary.FirstOrDefault(x => String.Equals(x.Key, myKey, comparer))?.Value;

或者,如果您愿意,不带LINQ:

1
2
3
4
5
6
7
8
9
10
11
12
var myKey = ...;
var myDictionary = ...;
var comparer = StringComparer.OrdinalIgnoreCase;
int? value;
foreach (var element in myDictionary)
{
  if (String.Equals(element.Key, myKey, comparer))
  {
    value = element.Value;
    break;
  }
}

这样可以节省创建新数据结构的成本,但作为回报,查找的成本是O(n)而不是O(1)。


对于从不使用常规字典构造函数的Linqers来说:

1
myCollection.ToDictionary(x => x.PartNumber, x => x.PartDescription, StringComparer.OrdinalIgnoreCase)


它不是很优雅,但如果你不能改变字典的创建,你所需要的只是一个肮脏的黑客,这怎么样:

1
2
3
4
5
var item = MyDictionary.Where(x => x.Key.ToLower() == MyIndex.ToLower()).FirstOrDefault();
    if (item != null)
    {
        TheValue = item.Value;
    }