我正在尝试实现IEqueatable,因此我可以在自定义类型LINQ查询中使用 .Except 。
自定义类型代码如下所示:
public class Case : IEquatable<Case>
{
[Key]
public int Id { get; set; }
//More properties
[...]
public bool Equals(Case other)
{
// Check whether the compared object references the same data.
if (ReferenceEquals(this, other)) return true;
// Check whether the compared object is null.
if (ReferenceEquals(other, null)) return false;
// Check whether the objects’ properties are equal.
return Id.Equals(other.Id);
}
public override bool Equals(object obj)
{
var other = obj as Case;
// Check whether the compared object references the same data.
if (ReferenceEquals(this, other)) return true;
// Check whether the compared object is null.
if (ReferenceEquals(other, null)) return false;
// Check whether the objects’ properties are equal.
return Id.Equals(other.Id);
}
public override int GetHashCode()
{
return Id.GetHashCode();
}
public static bool operator ==(Case case1, Case case2)
{
if ((object)case1 == null || (object)case2 == null)
return Equals(case1, case2);
return case1.Equals(case2);
}
public static bool operator !=(Case case1, Case case2)
{
if ((object)case1 == null || (object)case2 == null)
return !Equals(case1, case2);
return !case1.Equals(case2);
}
}
我在Equals方法中添加了throw new NotImplementedException();
,但它永远不会被调用。
我遵循了此处显示的约定: https://msdn.microsoft.com/en-us/library/ms131190.aspx
但没有成功。
修改
以下是调用Except方法的代码:
if (Checkset(set))
{
var subset = GetPowerSet(set);
var newset = powerset.Except(subset);
}
powerset
和subset
都是Case
的数组。
答案 0 :(得分:0)
在尝试使用linq查询之前,我建议您使用更简单的方法。即。
var case1_1 = new Case() { Id = 1 };
var case1_2 = new Case() { Id = 1 };
var areEqual = case1_1 == case1_2;
有了这个测试,这些是我能想到为什么你没有达到那个例外的原因:
Equals
方法,而您只从其中一个方法中抛出异常。Id
。如果GetHashCode
的结果不同,则甚至可能尝试来比较这些值。 答案 1 :(得分:0)
我有兴趣知道你是否尝试捕获Equals
的两个重载...从你的代码中弹出的唯一一件事是你有重复的实现来检查相等性。理想情况下,你只能在一个地方做到这一点。
以下是一个示例实现...您将EntityBase
替换为Case
...
/// <summary>
/// Indicates whether the current object is equal to another object of the same type.
/// </summary>
/// <returns> true if the current object is equal to the <paramref name="other" /> parameter; otherwise, false. </returns>
/// <param name="other"> An object to compare with this object. </param>
public bool Equals( EntityBase other ) {
return !ReferenceEquals(other, null)
&& Id.Equals(other.Id);
}
/// <summary>
/// Serves as a hash function for a particular type.
/// </summary>
/// <returns> A hash code for the current <see cref="T:System.Object" />. </returns>
/// <filterpriority> 2 </filterpriority>
public override int GetHashCode() {
return Id.GetHashCode();
}
/// <summary>
/// Determines whether the specified <see cref="T:System.Object" /> is equal to the current <see cref="T:System.Object" />.
/// </summary>
/// <returns> true if the specified object is equal to the current object; otherwise, false. </returns>
/// <param name="obj"> The object to compare with the current object. </param>
/// <filterpriority> 2 </filterpriority>
public override bool Equals( object obj ) {
return Equals(obj as EntityBase);
}
/// <summary>
/// Determines if the <paramref name="left" /> instance is considered equal to the <paramref name="right" /> object.
/// </summary>
/// <param name="left"> The instance on the left of the equality operator. </param>
/// <param name="right"> The instance on the right of the equality operator. </param>
/// <returns> True if the instances are considered equal, otherwise false. </returns>
public static bool operator ==( EntityBase left, EntityBase right ) {
return ReferenceEquals(left, null)
? ReferenceEquals(right, null)
: left.Equals(right);
}
/// <summary>
/// Determines if the <paramref name="left" /> instance is considered unequal to the <paramref name="right" /> object.
/// </summary>
/// <param name="left"> The instance on the left of the inequality operator. </param>
/// <param name="right"> The instance on the right of the inequality operator. </param>
/// <returns> True if the instances are considered unequal, otherwise false. </returns>
public static bool operator !=( EntityBase left, EntityBase right ) {
return !(left == right);
}
答案 2 :(得分:0)
如果你只打电话给:
var exceptList = list1.Except(list2);
没有返回任何列表,要执行枚举Except结果所需的比较,例如使用foreach:
foreach(var listElement in exceptList)
{
//...
}
然后调用GetHashCode和Equals方法。
修改强>: 此代码执行以下两个列表:
static void Main(string[] args)
{
List<MyClass> list1 = new List<MyClass>();
MyClass myClass1 = new MyClass() {Id = 1};
MyClass myClass2 = new MyClass() {Id = 2};
list1.Add(myClass1);
list1.Add(myClass2);
List<MyClass> list2 = new List<MyClass>();
list2.Add(myClass1);
var exceptList = list1.Except(list2);
foreach (var myClass in exceptList)
{
Console.WriteLine(myClass.Id);
}
}
public class MyClass : IEquatable<MyClass>
{
public int Id { get; set; }
public bool Equals(MyClass other)
{
return Id == other.Id;
}
public override int GetHashCode()
{
return Id;
}
}
此代码在控制台中打印“2”
答案 3 :(得分:0)
Equals
仅在必要时调用。处理IEquatable<T>
实现的所有LINQ方法首先使用(并存储)它们处理的对象的哈希码。如果两个对象具有相同的哈希码,则这些方法仅调用Equals
。
在您的数据中,没有相同Id
的情况,因此无需拨打Equals
。
这可以通过一个例子轻松证明。如果您有三个列表:
var list1 = new List<Case>
{
new Case{ Id = 1 },
new Case{ Id = 2 },
new Case{ Id = 3 }
};
var list2 = new List<Case>
{
new Case{ Id = 4 },
new Case{ Id = 5 },
new Case{ Id = 6 }
};
var list3 = new List<Case>
{
new Case{ Id = 1 },
new Case{ Id = 5 },
new Case{ Id = 6 }
};
然后是以下语句(在Equals
和GetHashCode
中有一些跟踪语句,而后者只是返回Id
)...
list1.Except(list2).ToList();
...将输出:
GetHashCode: 4
GetHashCode: 5
GetHashCode: 6
GetHashCode: 1
GetHashCode: 2
GetHashCode: 3
虽然声明......
list1.Except(list3).ToList();
...将输出:
GetHashCode: 1
GetHashCode: 5
GetHashCode: 6
GetHashCode: 1
Equals: 1 - 1
GetHashCode: 2
GetHashCode: 3