我正在学习字典,在这道题中迷失了方向。
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
我想要实现的是根据参数A1
和A2
得到B2
的值。我希望dict.ContainsKey(c)
返回true
,但由于某种原因它没有。
我可以这样做,它返回foo
,但这似乎是多余的?:
(from f in dict.Keys where f.A1==1 && f.A2==2 select dict[f].B2).First()
如果我知道A1
和A2
的值,我如何得到B2
的值?
当比较自定义类时,你应该解释。net如何在Equals
和GetHashCode
方法的帮助下完成它。如果不这样做,.net将比较引用,而不是值。在你的例子中,它可以是
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}");
您需要定义一个类,它实现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);
}
这是假的,因为c#中的类是引用类型,而a
和c
具有相同的值(即A1
和A2
是相同的),它们不是相同的实例,这是默认检查的。如果你愿意,你可以实现一个等价于a和它的值的IEqualityComparer,并将它的一个新实例传递给Dictionary构造函数