问题描述
我知道我可以使用System.ValueTuple键(基于this answer)定义字典,如下所示:
var multiKeyDictionary = new Dictionary<(int key1,string key2),object>()
{
{(1,"test"),new object() }
};
但是,我希望string
中存在的任何ValueTuple
值都可以使用IEqualityComparer
或不区分大小写的方式被视为不区分大小写,类似于{{3 }}。
到目前为止,我想到的解决方案是:
- prescribed here
- 按如下所示包装对字典的所有访问权限:
class InsensitiveValueTupleDictionary
{
private Dictionary<(int key1,object> _multiKeyDictionary = new Dictionary<(int key1,object>();
public void Add((int key1,string key2) key,object value)
{
_multiKeyDictionary.Add((key.key1,key.key2.ToLower()),value);
}
public bool ContainsKey((int key1,string key2) key)
{
return _multiKeyDictionary.ContainsKey((key.key1,key.key2.ToLower()));
}
// ... and so on
}
这两种策略都需要为ValueTuple
(例如,(int,string)
,(string,int)
,(string,string,int)
等)的每个唯一组合设置代码。
是否存在另一种允许任意ValueTuple
组合使用不区分大小写的键相等的方法?
解决方法
您正在使用元组将自己绘画到那个角落。元组只代表一袋价值,而不是一个实体。
您可以以元组友好的方式实现自己的键类型:
public struct Key : IEquatable<Key>
{
private readonly int hashCode;
public Key(int key1,string key2)
{
this.Key1 = key1;
this.Key2 = key2;
this.hashCode = HashCode.Combine(key1,StringComparer.OrdinalIgnoreCase.GetHashCode(Key2));
}
public int Key1 { get; }
public string Key2 { get; }
public bool Equals(Key other)
=> this.hashCode == other.hashCode
&& this.Key1 == other.Key1
&& string.Equals(this.Key2,other.Key2,StringComparison.OrdinalIgnoreCase);
public override bool Equals(object obj)
=> obj is Key key && this.Equals(key);
public override int GetHashCode() => this.hashCode;
public static implicit operator (int key1,string key2)(Key key)
=> (key1: key.Key1,key2: key.Key2);
public static implicit operator Key((int key1,string key2) key)
=> new Key(key.key1,key.key2);
public void Deconstruct(out int key1,out string key2)
=> (key1,key2) = (this.Key1,this.Key2);
}
您甚至可以将其与元组或“喜欢”元组一起使用:
var key = new Key(1,"one");
var (k1,k2) = key;
(int key1,string key2) t = key;
t.key1 = 2;
t.key2 = "two";
key = t;
如果您真的想保留元组,请定义自己的比较器:
public class MyTupleComparer : IEqualityComparer<(int key1,string key2)>
{
public bool Equals((int key1,string key2) x,(int key1,string key2) y)
=> x.key1 == y.key1
&& string.Equals(x.key2,y.key2,StringComparison.OrdinalIgnoreCase);
public int GetHashCode((int key1,string key2) obj)
=> HashCode.Combine(obj.key1,StringComparer.OrdinalIgnoreCase.GetHashCode(obj.key2));
}