如何使用 ValueTuples 创建通用的不区分大小写的多键字典?
How can I create a generic case-insensitive multi-key dictionary using ValueTuples?
我知道我可以用 System.ValueTuple key (based on ) 定义字典,如下所示:
var multiKeyDictionary = new Dictionary<(int key1, string key2), object>()
{
{(1, "test"), new object() }
};
但是,我希望 ValueTuple
中存在的任何 string
值都被视为不区分大小写,使用 IEqualityComparer
或类似惯用的字典访问方式,类似于 prescribed here.
目前我想到的解决办法是:
- Implement IEqualityComparer like was necessary for
System.Tuple
- 将对字典的所有访问包装如下:
class InsensitiveValueTupleDictionary
{
private Dictionary<(int key1, string key2), object> _multiKeyDictionary = new Dictionary<(int key1, string key2), 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));
}
我知道我可以用 System.ValueTuple key (based on
var multiKeyDictionary = new Dictionary<(int key1, string key2), object>()
{
{(1, "test"), new object() }
};
但是,我希望 ValueTuple
中存在的任何 string
值都被视为不区分大小写,使用 IEqualityComparer
或类似惯用的字典访问方式,类似于 prescribed here.
目前我想到的解决办法是:
- Implement IEqualityComparer like was necessary for
System.Tuple
- 将对字典的所有访问包装如下:
class InsensitiveValueTupleDictionary
{
private Dictionary<(int key1, string key2), object> _multiKeyDictionary = new Dictionary<(int key1, string key2), 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));
}