如何使用ValueTuples创建通用的不区分大小写的多键字典?

问题描述

我知道我可以使用System.ValueTuple键(基于this answer)定义字典,如下所示:

var multiKeyDictionary = new Dictionary<(int key1,string key2),object>()
{
    {(1,"test"),new object() }
};

但是,我希望string中存在的任何ValueTuple值都可以使用IEqualityComparer或不区分大小写的方式被视为不区分大小写,类似于{{3 }}。

到目前为止,我想到的解决方案是:

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));
}

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...