Is there an effective way to determine whether .Equals on two different but "equal" instances will return true?
I'm attempting to use reflection to determine the result of a call to .Equals on two different but "equal" instances of a type.
My method would be something like:
public static bool TypeComparesProperties(Type t)
{
// return true if (an instance of t).Equals(a different instance of t)
// will be true if all publicly accessible properties of the instances
// are the same
}
By way of example:
string a = "Test";
string b = "Test";
bool areEqual = a.Equals(b); // areEqual will be true
// so:
TypeComparesProperties(typeof(string)); // should return true
However, given:
public class MyComplexType
{
public int Id { get; set; }
public string MyString { get; set; }
}
MyComplexType a = new MyComplexType {Id = 1, MyString = "Test"};
MyComplexType b = new MyComplexType { Id = 1, MyString = "Test" };
bool areEqual = a.Equals(b); // areEqual will be false
// so:
TypeComparesProperties(typeof(MyComplexType)); // should return false
If I implemented IEquatable<MyComplexType>
on my class as follows, I'd get true instead:
public class MyComplexType : IEquatable<MyComplexType>
{
public int Id { get; set; }
pub开发者_JAVA百科lic string MyString { get; set; }
public bool Equals(MyComplexType other)
{
return (Id.Equals(other.Id) && MyString.Equals(other.MyString));
}
}
I figure I can probably do it by instantiating two instances using reflection, then setting all properties to appropriately typed default values. That's a lot of work though and a lot of overhead, and I think I'd run into problems if there was no empty constructor on the type.
Any other ideas?
Edit:
It seems that people are confused by my intentions. I apologise. Hopefully this will clarify:
I have a method which should compare two objects to the best of its abilities. Simply calling .Equals() won't suffice, because either:
- The objects will be value types or will implement IEquatable in a nice way and I'll get a true response. Great!
- The objects may have all the same properties and be "equal", but because they're different instances, I'll get a false response. I can't tell whether this false is because the objects are not "equal", or because they're just different instances.
So in my mind, the comparison method should:
- Examine the object type to see whether it's
Equals
method will return true for two different instances with the same public properties. - If so, call the
Equals
method and return the result - If not, have a look at all the properties and fields and compare them as well as I can to determine whether they're equal
Now, I understand that I could just skip to step 3, but if there's a way to determine ahead of time whether it's necessary, that'd be a time-saver.
Edit 2:
I'm gonna close this for a couple of reasons:
- The more I talk about it, the more I realise that what I asked isn't what I really wanted to do
- Even if I did want to do this, there's no real shortcut at all. RE the earlier edit, I should just skip to step 3 anyway.
Thanks all for your input.
You could do something based on this answer, noting that this compares the public properties, not the fields, and that Equals
could do anything crazy it wants. It wouldn't be hard to change it to use fields instead, but... to be honest, I'm not sure what the driver is here. I'd just write the Equals(object)
and Equals(MyComplexType)
and use EqualityComparer<T>.Default.Equals(x,y)
(which handles IEquatable<T>
, nulls, Nullable<T>
, etc - using object.Equals(x,y)
as the fallback strategy).
For something that I think meets your updated need:
public static bool AreEqual<T>(T x, T y) {
if(ReferenceEquals(x,y)) return true;
if(x==null || y == null) return false;
IEquatable<T> eq = x as IEquatable<T>;
if(eq == null) return PropertyCompare.Equal(x,y);
return eq.Equals(y);
}
Honestly, if your comparing valuetypes the default equals should be fine. However when using the default implementation of equals on reference types it operates differently, more of a reference pointer equallity. To get true object level Equals operations to work you either have to implement IEquatable, override the Equals method on each class, or use reflection to compare each public property. Take a look at this link and it may or may not help:
SO - Internal Equals Object
Try this on for size.
public static bool TypeComparesProperties(Type t)
{
Type equatableInterface = typeof(IEquatable<>);
if (t.GetInterface(equatableInterface.Name) != null)
{
return true;
}
else
{
Type objectClass = typeof(Object);
MethodInfo equalsMethod = t.GetMethod("Equals", new Type[] { typeof(object) });
return equalsMethod.DeclaringType != objectClass;
}
}
First, the method checks to see if IEquatable<>
has been implemented on the type. If it has, return true. If it hasn't, check to see if the type has overridden the Equals(object)
method. If it has, return true; otherwise (if the Equals
method is the default method declared in Object
), return false.
精彩评论