可互换的多键词典

时间:2018-03-28 07:27:22

标签: c# dictionary

我有很多实体需要在他们之间共享数据。两个实体都将从此词典中请求值。

public class Key {
    public string nameA;
    public string nameB;
}
public class SharedValue {
    public int id;
}

private Dictionary<Key, SharedValue> relation = new Dictionary<Key, SharedValue>();

然后加入字典。

relation.Add(new Key(){ nameA = "User1", nameB = "User2" }, new SharedValue(){ id = -11 });

最后,我希望无论nameA或nameB的顺序如何,我都可以获得共享的SharedValue。

relation[new Key(){ nameA = "User1", nameB = "User2" }].id  // Get -11
relation[new Key(){ nameA = "User2", nameB = "User1" }].id  // Get -11

3 个答案:

答案 0 :(得分:1)

为您的密钥类定义EqualsGeyHashCode方法:

    public class Key
    {
        public string nameA;
        public string nameB;

        public override bool Equals(object obj)
        {
            return base.Equals(obj as Key);
        }

        protected bool Equals(Key other)
        {
            return string.Equals(nameA, other.nameA) && string.Equals(nameB, other.nameB) ||
                   string.Equals(nameA, other.nameB) && string.Equals(nameB, other.nameA);
        }

        public override int GetHashCode()
        {
            return (nameA?.GetHashCode() ^ nameB?.GetHashCode()) ?? 0;
        }
    }

答案 1 :(得分:1)

您可以提供一个cutom IEqualityComparer<Key>,您可以将其用于字典构造函数(以及许多LINQ方法):

public class UnorderedKeyComparer : IEqualityComparer<Key>
{
    public bool Equals(Key x, Key y)
    {
        if (object.ReferenceEquals(x, y))
            return true;
        if (x == null || y == null)
            return false;
        if (string.Equals(x.NameA, y.NameA) && string.Equals(x.NameB, y.NameB))
            return true;
        if (string.Equals(x.NameA, y.NameB) && string.Equals(x.NameB, y.NameA))
            return true;
        return false;
    }

    public int GetHashCode(Key obj)
    {
        return (obj?.NameA?.GetHashCode() ?? int.MinValue) ^ (obj?.NameB?.GetHashCode() ?? int.MinValue);
    }
}

因此,在这种情况下,您只需要使用UnorderedKeyComparer初始化字典:

Dictionary<Key, SharedValue> Relation = new Dictionary<Key, SharedValue>(new UnorderedKeyComparer());

顺便说一句,我无法抗拒修复你的命名问题。

答案 2 :(得分:0)

您有很多选择,例如:

  1. 实施IEqualityComparer<YourKey>并传递一个实例 class实现IEqualityComparer<YourKey>到构造函数 字典
  2. 仅在您的自定义密钥上实施IEquatable<T>
  3. 这是Option 2

    的方法
    public class Key:IEquatable<Key> {
        public string nameA;
        public string nameB;
    
        public bool Equals(Key other)
        {
            if(other == null)
                return false;
            if(ReferenceEquals(this,other))
                return true;
            return (string.Equals(this.nameA,other.nameA) && string.Equals(this.nameB,other.nameB))
                    || (string.Equals(this.nameA,other.nameB) && string.Equals(this.nameB,other.nameA));
        }
        public override bool Equals(object obj){
            if(obj == null)
                return false;
            if(ReferenceEquals(obj,this))
                return true;
            return Equals((Key)obj);
        }
        public override int GetHashCode(){
            return (nameA?.GetHashCode() ^ nameB?.GetHashCode()) ?? 0;
        }
     }
    

    测试:

    private static Dictionary<Key, SharedValue> relation = new Dictionary<Key, SharedValue>();
    
    static void Main(string[] args)
    {
        relation.Add(new Key{nameA="a",nameB="b"},new SharedValue{id=1});
        if(relation.ContainsKey(new Key{nameA="a",nameB="b"})){
            Console.WriteLine("YES");
        }
        if(relation.ContainsKey(new Key{nameA="b",nameB="a"})){
            Console.WriteLine("YES");
        }
        else Console.WriteLine("NO");
    }
    

    输出:

    YES
    YES