C# 压倒一切的IEquatable<;T>;当T是接口且派生类型之间的哈希代码不同时
我有C# 压倒一切的IEquatable<;T>;当T是接口且派生类型之间的哈希代码不同时,c#,.net,interface,gethashcode,iequatable,C#,.net,Interface,Gethashcode,Iequatable,我有A和B两个类都实现了接口I public interface I { int SomeInt { get; } bool SomeBool { get; } float SomeFloat { get; } } public class A : I { public int SomeInt { get; } public bool SomeBool { get; } public float SomeFloat { get; }
A
和B
两个类都实现了接口I
public interface I
{
int SomeInt { get; }
bool SomeBool { get; }
float SomeFloat { get; }
}
public class A : I
{
public int SomeInt { get; }
public bool SomeBool { get; }
public float SomeFloat { get; }
private readonly string _someARelatedStuff;
// Rest of class...
}
public class B : I
{
public int SomeInt { get; }
public bool SomeBool { get; }
public float SomeFloat { get; }
private string readonly _someBRelatedStuff;
private double readonly _someOtherBRelatedStuff;
// Rest of class...
}
有时我想基于I
属性的相等性(SomeInt
,SomeBool
,SomeFloat
)来测试A
和B
之间的相等性(通常在比较A
列表和B
列表时),因此,我在这两个方面都实现了IEquatable
,并根据它们共享的I
属性值对它们进行了比较
问题是我已经在A和B上实现了GetHashCode()
,它会产生不同的散列,因为我考虑了其他成员
B
不依赖于A
,所以我使用接口I
来比较它们,它有一个带有getter的属性列表
我读到:
如果您正在实现一个类,您应该始终确保两个相等的对象具有相同的哈希代码
那么,这是否意味着每当类a
想要成为实现接口I
,并且我想要能够比较实现I
的实例时,我必须确保对I
的所有实例都以相同的方式计算hashcode,并且只使用I
属性
当T是一个接口时,我确实觉得我不打算实现IEquatable
,但我的备选方案是:
C
类派生,由于单一继承,这个解决方案将不起作用A
或B
上的方法执行A
和B
之间的相等性检查-将创建代码重复I
中定义的I
实例之间使用相等检查方法-听起来是最好的选择是否有我缺少的选项?考虑使用a
IEqualityComparer
类来比较常用值
为了便于阅读,我已将界面重命名为ICommon
公共接口ICommon
{
int SomeInt{get;}
bool SomeBool{get;}
float SomeFloat{get;}
}
公共类CommonComparer:IEqualityComparer
{
公共布尔等于(ICommon x,ICommon y)
{
返回x.SomeInt.Equals(y.SomeInt)
&&x.SomeBool等于(y.SomeBool)
&&x.SomeFloat等于(y.SomeFloat);
}
公共int GetHashCode(ICommon obj)
{
未经检查
{
int hc=-1817952719;
hc=(-1521134295)*hc+obj.SomeInt.GetHashCode();
hc=(-1521134295)*hc+obj.SomeBool.GetHashCode();
hc=(-1521134295)*hc+obj.SomeFloat.GetHashCode();
返回hc;
}
}
}
该程序可以区分两个列表中相同的项目
class Program
{
static void Main(string[] args)
{
var listA = new List<A>
{
new A(1001, true, 1.001f, "A1"),
new A(1002, true, 1.002f, "A2"),
new A(1003, false, 1.003f, "A1"),
new A(1004, false, 1.004f, "A4")
};
var listB = new List<B>
{
new B(1001, true, 1.001f, "B1", 2.5),
new B(1002, false, 1.002f, "B2", 2.8),
new B(1003, true, 1.003f, "B3", 2.9),
new B(1004, false, 1.004f, "B4", 2.9)
};
var common = Enumerable.Intersect(listA, listB, new CommonComparer()).OfType<ICommon>();
Console.WriteLine($"{"SomeInt",-8} {"Bool",-6} {"SomeFloat",-10}");
foreach (var item in common)
{
Console.WriteLine($"{item.SomeInt,-8} {item.SomeBool,-6} {item.SomeFloat,-10}");
}
//SomeInt Bool SomeFloat
//1001 True 1.001
//1004 False 1.004
}
}
类程序
{
静态void Main(字符串[]参数)
{
var listA=新列表
{
新A(1001,正确,1.001f,“A1”),
新A(1002,真,1.002f,“A2”),
新A(1003,假,1.003f,“A1”),
新A(1004,假,1.004f,“A4”)
};
var listB=新列表
{
新B(1001,正确,1.001f,“B1”,2.5),
新B(1002,假,1.002f,“B2”,2.8),
新B(1003,正确,1.003f,“B3”,2.9),
新B(1004,假,1.004f,“B4”,2.9)
};
var common=Enumerable.Intersect(listA、listB、new CommonComparer())。of type();
WriteLine($“{”SomeInt“,-8}{”Bool“,-6}{”SomeFloat“,-10}”);
foreach(通用var项目)
{
WriteLine($“{item.SomeInt,-8}{item.SomeBool,-6}{item.SomeFloat,-10}”);
}
//有点像有点像浮球
//1001真1.001
//1004假1.004
}
}
以及其余的代码定义
public class A : ICommon, IEquatable<A>
{
static readonly CommonComparer comparer = new CommonComparer();
public int SomeInt { get; }
public bool SomeBool { get; }
public float SomeFloat { get; }
private readonly string _someARelatedStuff;
// Rest of class...
public A(ICommon other, string someARelatedStuff)
: this(other.SomeInt, other.SomeBool, other.SomeFloat, someARelatedStuff)
{ }
public A(int someInt, bool someBool, float someFloat, string someARelatedStuff)
{
this.SomeInt = someInt;
this.SomeBool = someBool;
this.SomeFloat = someFloat;
this._someARelatedStuff = someARelatedStuff;
}
public override string ToString() => _someARelatedStuff;
#region IEquatable Members
public override bool Equals(object obj)
{
if (obj is A other)
{
return Equals(other);
}
return false;
}
public virtual bool Equals(A other)
{
return comparer.Equals(this, other)
&& _someARelatedStuff.Equals(other._someARelatedStuff);
}
public override int GetHashCode()
{
unchecked
{
int hc = comparer.GetHashCode(this);
hc = (-1521134295)*hc + _someARelatedStuff.GetHashCode();
return hc;
}
}
#endregion
}
public class B : ICommon, IEquatable<B>
{
static readonly CommonComparer comparer = new CommonComparer();
public int SomeInt { get; }
public bool SomeBool { get; }
public float SomeFloat { get; }
readonly string _someBRelatedStuff;
readonly double _someOtherBRelatedStuff;
// Rest of class...
public B(ICommon other, string someBRelatedStuff, double someOtherBRelatedStuff)
: this(other.SomeInt, other.SomeBool, other.SomeFloat, someBRelatedStuff, someOtherBRelatedStuff)
{ }
public B(int someInt, bool someBool, float someFloat, string someBRelatedStuff, double someOtherBRelatedStuff)
{
this.SomeInt = someInt;
this.SomeBool = someBool;
this.SomeFloat = someFloat;
this._someBRelatedStuff = someBRelatedStuff;
this._someOtherBRelatedStuff = someOtherBRelatedStuff;
}
public override string ToString() => $"{_someBRelatedStuff}, {_someOtherBRelatedStuff.ToString("g4")}";
#region IEquatable Members
public override bool Equals(object obj)
{
if (obj is B other)
{
return Equals(other);
}
return false;
}
public virtual bool Equals(B other)
{
return comparer.Equals(this, other)
&& _someBRelatedStuff.Equals(other._someBRelatedStuff)
&& _someOtherBRelatedStuff.Equals(other._someOtherBRelatedStuff);
}
public override int GetHashCode()
{
unchecked
{
int hc = comparer.GetHashCode(this);
hc = (-1521134295)*hc + _someBRelatedStuff.GetHashCode();
hc = (-1521134295)*hc + _someOtherBRelatedStuff.GetHashCode();
return hc;
}
}
#endregion
}
公共A类:ICommon,IEquatable
{
静态只读CommonComparer comparer=新CommonComparer();
公共int SomeInt{get;}
公共bool SomeBool{get;}
公共浮点SomeFloat{get;}
私有只读字符串_somearestuff;
//其他同学。。。
公共A(ICommon-other,字符串someAreatedStuff)
:此(other.SomeInt,other.SomeBool,other.SomeFloat,someARelatedStuff)
{ }
公共A(int-someInt,bool-someBool,float-someFloat,string-someARelatedStuff)
{
this.SomeInt=SomeInt;
this.SomeBool=SomeBool;
this.SomeFloat=SomeFloat;
这._somearestuff=somearestuff;
}
公共重写字符串ToString()=>\u someARelatedStuff;
#区域可容纳成员
公共覆盖布尔等于(对象对象对象)
{
如果(obj是另一个)
{
回报等于(其他);
}
返回false;
}
公共虚拟布尔等于(其他)
{
返回比较器.Equals(此,其他)
&&_somearestuff.等于(其他._somearestuff);
}
公共覆盖int GetHashCode()
{
未经检查
{
int hc=comparer.GetHashCode(this);
hc=(-1521134295)*hc+_somearestuff.GetHashCode();
返回hc;
}
}
#端区
}
公共B类:ICommon,IEquatable
{
静态只读CommonComparer comparer=新CommonComparer();
公共int SomeInt{get;}
公共bool SomeBool{get;}
公共浮点SomeFloat{get;}
只读字符串_someBRelatedStuff;
只读双_someotherbreatedstuff;
//其他同学。。。
公共B(ICommon other,字符串someBRelatedStuff,double someOtherBRelatedStuff)
:此(other.SomeInt,other.SomeBool,other.SomeFloat,someBRelatedStuff,someOtherBRelatedStuff)
{ }
公共B(int-someInt,bool-someBool,float-someFloat,
public class A : ICommon, IEquatable<A>
{
static readonly CommonComparer comparer = new CommonComparer();
public int SomeInt { get; }
public bool SomeBool { get; }
public float SomeFloat { get; }
private readonly string _someARelatedStuff;
// Rest of class...
public A(ICommon other, string someARelatedStuff)
: this(other.SomeInt, other.SomeBool, other.SomeFloat, someARelatedStuff)
{ }
public A(int someInt, bool someBool, float someFloat, string someARelatedStuff)
{
this.SomeInt = someInt;
this.SomeBool = someBool;
this.SomeFloat = someFloat;
this._someARelatedStuff = someARelatedStuff;
}
public override string ToString() => _someARelatedStuff;
#region IEquatable Members
public override bool Equals(object obj)
{
if (obj is A other)
{
return Equals(other);
}
return false;
}
public virtual bool Equals(A other)
{
return comparer.Equals(this, other)
&& _someARelatedStuff.Equals(other._someARelatedStuff);
}
public override int GetHashCode()
{
unchecked
{
int hc = comparer.GetHashCode(this);
hc = (-1521134295)*hc + _someARelatedStuff.GetHashCode();
return hc;
}
}
#endregion
}
public class B : ICommon, IEquatable<B>
{
static readonly CommonComparer comparer = new CommonComparer();
public int SomeInt { get; }
public bool SomeBool { get; }
public float SomeFloat { get; }
readonly string _someBRelatedStuff;
readonly double _someOtherBRelatedStuff;
// Rest of class...
public B(ICommon other, string someBRelatedStuff, double someOtherBRelatedStuff)
: this(other.SomeInt, other.SomeBool, other.SomeFloat, someBRelatedStuff, someOtherBRelatedStuff)
{ }
public B(int someInt, bool someBool, float someFloat, string someBRelatedStuff, double someOtherBRelatedStuff)
{
this.SomeInt = someInt;
this.SomeBool = someBool;
this.SomeFloat = someFloat;
this._someBRelatedStuff = someBRelatedStuff;
this._someOtherBRelatedStuff = someOtherBRelatedStuff;
}
public override string ToString() => $"{_someBRelatedStuff}, {_someOtherBRelatedStuff.ToString("g4")}";
#region IEquatable Members
public override bool Equals(object obj)
{
if (obj is B other)
{
return Equals(other);
}
return false;
}
public virtual bool Equals(B other)
{
return comparer.Equals(this, other)
&& _someBRelatedStuff.Equals(other._someBRelatedStuff)
&& _someOtherBRelatedStuff.Equals(other._someOtherBRelatedStuff);
}
public override int GetHashCode()
{
unchecked
{
int hc = comparer.GetHashCode(this);
hc = (-1521134295)*hc + _someBRelatedStuff.GetHashCode();
hc = (-1521134295)*hc + _someOtherBRelatedStuff.GetHashCode();
return hc;
}
}
#endregion
}