【问题标题】:Reading info from Dictionary从字典中读取信息
【发布时间】:2021-09-28 08:42:27
【问题描述】:

我正在学习字典,迷失在这个问题中。

class Program
{
    static void Main(string[] args)
    {
        Dictionary<A, B> dict = new Dictionary<A, B>();
        A a = new A { A1 = 1, A2 = 2 };
        B b = new B { B1 = 3, B2 = "foo" };
        dict.Add(a, b);
        A c = new A { A1 = 1, A2 = 2 };

        Console.WriteLine($"dict.ContainsKey(a): {dict.ContainsKey(a)}");
        Console.WriteLine($"dict.ContainsKey(c): {dict.ContainsKey(c)}");
        Console.ReadLine();
    }
}
class A
{
    public int A1 { get; set; }
    public int A2 { get; set; }
}

class B
{
    public int B1 { get; set; }
    public string  B2 { get; set; }
}

这段代码的输出是:

dict.ContainsKey(a): True
dict.ContainsKey(c): False

我想要实现的是基于参数A1A2获取B2的值。我希望dict.ContainsKey(c) 返回true,但由于某种原因它没有。

我可以做这样的事情,返回foo,但这似乎有点矫枉过正?:

(from f in dict.Keys where f.A1==1 && f.A2==2 select dict[f].B2).First()

如果我知道A1A2 的值,如何获得B2 的值?

【问题讨论】:

  • 虽然 a 和 c 共享相同的值,但它们是不同的对象,具有不同的引用。 a!=c。这就是你所说的“某种原因”
  • 这是错误的,因为 C# 中的类是引用类型,而 ac 具有相同的值(即 A1 和 A2 相同)它们不是同一个实例,这就是默认选中。如果你愿意,你可以实现一个IEqualityComparer,它将A 等同于它的值,并将它的一个新实例传递给 Dictionary 构造函数
  • 虽然 a 和 c 共享相同的值但引用不同

标签: c# dictionary


【解决方案1】:

在比较自定义类时,您应该在EqualsGetHashCode 方法的帮助下解释.net 如何做到这一点。 如果您不这样做,.net 将比较 references,而不是 values。在你的情况下,它可以是

class A {
  public int A1 { get; set; }
  public int A2 { get; set; }

  public override bool Equals(object obj) =>
    (obj is A other) && (A1 == other.A1) && (A2 == other.A2); 
  
  public override int GetHashCode() => unchecked((A1 << 16) ^ A2); 

  // For debugging
  public override string ToString() => $"A1 = {A1}; A2 = {A2}";
}

现在

 Dictionary<A, B> dict = new Dictionary<A, B>() {
   {new A { A1 = 1, A2 = 2 }, new B { B1 = 3, B2 = "foo" }},
 };

 A c = new A { A1 = 1, A2 = 2 };

 if (dict.ContainsKey(c))
   Console.WriteLine($"Contains {c}");
 else
   Console.WriteLine($"Doesn't contains {c}"); 

【讨论】:

    【解决方案2】:

    您需要定义一个类,该类实现IEqualityComparer 来定义如何比较键。您想根据它们的属性而不是它们的引用来比较它们。

    class AValueComparer : IEqualityComparer<A>
    {
        public bool Equals(A x, A y) => x.A1 == y.A1 && x.A2 == y.A2;
        public int GetHashCode([DisallowNull] A obj) => HashCode.Combine(obj.A1, obj.A2);
    }
    

    那么您只需将此比较器连接到您的字典。

    [Fact]
    public void Test1()
    {
        //Arrange
        var dict = new Dictionary<A, B>(new AValueComparer());
        var a = new A { A1 = 1, A2 = 2 };
        var b = new B { B1 = 3, B2 = "foo" };
        dict.Add(a, b);
        var c = new A { A1 = 1, A2 = 2 };
    
        //Act
        var doesAExist = dict.ContainsKey(a);
        var doesCExist = dict.ContainsKey(c);
    
        //Assert
        Assert.Equal(doesAExist, doesCExist);
    }
    

    【讨论】:

    • 我会将该类重命名为更能表明其目的的名称,例如 AValueComparer,但是是的,这就是这样做的方法
    • @MindSwipe 是的,这是有道理的。我已经改名了。
    • 这是比较两个布尔值?
    • @Luuk 你的意思是测试吗?是的,Assert.Equal 比较两个 bool 变量。
    • 如果我没有遗漏什么,这不起作用:您需要一个 GetHashCode 实现为 Equals 对象返回相同的哈希值,而默认的 GetHashCode 没有。 Here 一个例子
    【解决方案3】:

    这是错误的,因为 C# 中的类是引用类型,而 ac 具有相同的值(即 A1A2 相同)它们不是同一个实例,这是检查的内容默认。如果你愿意,你可以实现一个 IEqualityComparer ,它将 A 等同于它的值,并将它的一个新实例传递给 Dictionary 构造函数

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-09-23
      • 2022-11-19
      • 2018-08-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-02-24
      相关资源
      最近更新 更多