Reputation: 5414
Given an instance of an object in C#, how can I determine if that object has value semantics? In other words, I want to guarantee that an object used in my API is suitable to be used as a dictionary key. I was thinking about something like this:
var type = instance.GetType();
var d1 = FormatterServices.GetUninitializedObject(type);
var d2 = FormatterServices.GetUninitializedObject(type);
Assert.AreEqual(d1.GetHashCode(), d2.GetHashCode());
What do you think of that approach?
Upvotes: 5
Views: 234
Reputation: 15415
You can test for implementation of Equals()
and GetHashCode()
with this:
s.GetType().GetMethod("GetHashCode").DeclaringType == s.GetType()
or rather per @hvd's suggestion:
s.GetType().GetMethod("GetHashCode").DeclaringType != typeof(object)
Some some object s, if GetHashCode()
is not implemented by it's type, this will be false, otherwise true.
One thing to be careful on is that this will not protect against a poor implementation of Equals()
or GetHashCode()
- this would evaluate to true even if the implementation was public override int GetHashCode() { }
.
Given the drawbacks, I would tend towards documenting your types ("this type should / should not be used for a dictionary key..."), because this isn't something you could ultimately depend upon. If the implementation of Equals()
or GetHashCode()
was flawed instead of missing, it would pass this test but still have a run-time error.
Upvotes: 4
Reputation: 144116
You can see if an object defines its own Equals
and GetHashCode
using the DeclaringType
property on the corresponding MethodInfo
:
bool definesEquality = type.GetMethod("Equals", new[] { typeof(object) }).DelcaringType == type && type.GetMethod("GetHashCode", Type.EmptyTypes).DeclaringType == type;
Upvotes: 1
Reputation: 73442
FormatterServices.GetUninitializedObject
can put the object in an invalid state; It breaks the guaranteed assignment of readonly fields etc. Any code which assumes that fields will not be null
will break. I wouldn't use that.
You can check whether GetHashCode
and Equals
is overridden via reflection, but that's not enough. You could override the method call base class method. That doesn't count as value semantics.
Btw value semantics doesn't mean equal hashcodes. It could be a collision too; Value semantics means that two objects with equals properties should return same hashcode as well as equals method should evaluate to true.
I suggest you to create an instance, assign some properties, clone it; Now both hashcodes should be equal and calling object.Equals(original, clone)
should evaluate to true.
Upvotes: 3