我正在尝试实现IEqueatable,所以我可以使用.除了在我的自定义类型 LINQ 查询中。
自定义类型代码如下所示:
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
和这里https://blogs.msdn.microsoft.com/csharpfaq/2009/03/25/how-to-use-linq-methods-to-compare-objects-of-custom-types/
但没有成功。
编辑
下面是调用 Except 方法的代码:
if (Checkset(set))
{
var subset = GetPowerSet(set);
var newset = powerset.Except(subset);
}
其中powerset
和subset
都是Case
数组。
在尝试使用 linq 查询执行操作之前,我建议使用更简单的方法。 即
var case1_1 = new Case() { Id = 1 };
var case1_2 = new Case() { Id = 1 };
var areEqual = case1_1 == case1_2;
有了这个测试,这些是我能想到为什么你没有达到那个异常的原因:
- 您有 2 个
Equals
方法,并且您只从其中 1 个中抛出了异常。 - 您比较的 2 个对象没有相同的
Id
。 如果GetHashCode
的结果不同,它甚至可能不会尝试比较这些值。 - 捕获了异常
想知道您是否尝试在两个重载中捕获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);
}
如果您只调用 Except:
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">
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