C# collection with NSubstitue proxy objects overwrite Equals - c#

I had a problem with using .NET collections with Nsubstitue objects.
I have a base class where I implement Equals(object), CompareTo function
In the test I create two exact Nsubstitue object proxy for this base class.
After I put the object in the collection, the collection shows that these two object proxy are two different objects.
I wonder what could be the reason of this behavior, and how to define the a collection with mockups.
public class KeyTestClass : IKeyTestClass
{
public int Id { get; private set; }
public KeyTestClass()
{
Id = 1;
}
public override int GetHashCode()
{
return Id;
}
public int CompareTo(IKeyTestClass other)
{
return Id - other.Id;
}
public bool Equals(IKeyTestClass other)
{
return Id == other.Id;
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != GetType()) return false;
return Equals((KeyTestClass)obj);
}
}
public interface IKeyTestClass : IComparable<IKeyTestClass>, IEquatable<IKeyTestClass>
{
int Id { get; }
}
public class KeyTestClass2 : IKeyTestClass2
{
}
public interface IKeyTestClass2
{
}
[TestClass]
public class ConsistencyRelatedTests
{
[TestMethod]
public void ValidateTestClass()
{
var dic = new Dictionary<IKeyTestClass,List<IKeyTestClass2>>();
// using new equals function defined by Nsubstittue.
var item1 = Substitute.For<IKeyTestClass>();
var item2 = Substitute.For<IKeyTestClass>();
item1.Id.Returns(1);
item2.Id.Returns(1);
Assert.IsTrue(item1.Equals(item2)); //false, not working
dic.Add(item1, new List<IKeyTestClass2>());
dic.Add(item2, new List<IKeyTestClass2>());
// Using real class equals method
var item3 = new KeyTestClass();
var item4 = new KeyTestClass();
Assert.IsTrue(item3.Equals(item4)); //working
dic.Add(item3, new List<IKeyTestClass2>());
dic.Add(item4, new List<IKeyTestClass2>());
}
}

In this example Equals() is implemented for KeyTestClass. That does not mean it applies to all instances of the IKeyTestClass. If we create another class KeyTestClass2 : IKeyTestClass and use default Equals we'd get exactly the same result:
var item1 = new KeyTestClass2();
var item2 = new KeyTestClass2();
Assert.IsTrue(item1.Equals(item2)); // also fails, as expected
This is pretty much what NSubstitute does when we call Substitute.For<IKeyTestClass>(). It creates a new class implementing the interface, so it is completely unaware of the KeyTestClass.Equals implementation.
There are a few options here depending on what you are trying to do. Firstly, your KeyTestClass.Equals works with all IKeyTestClass instances, including substitutes, so you can use that fine:
var item1 = new KeyTestClass();
var item2 = Substitute.For<IKeyTestClass>();
var item3 = Substitute.For<IKeyTestClass>();
item2.Id.Returns(1);
item3.Id.Returns(42);
Assert.IsTrue(item1.Equals(item2)); // Passes (as expected)
Assert.IsFalse(item1.Equals(item3)); // Passes (as expected)
Secondly, you could substitute the IEquatable<IKeyTestClass>.Equals method on the substitutes (NOTE: not for Object.Equals, that can cause problems).
var item1 = Substitute.For<IKeyTestClass>();
var item2 = Substitute.For<IKeyTestClass>();
item1.Id.Returns(1);
item2.Id.Returns(1);
item1.Equals(item2).Returns(true);
Assert.IsTrue(item1.Equals(item2)); // Passes as expected
In this case you may want to also stub out item2.Equals(item1). We can also delegate to the real logic with item1.Equals(Arg.Any<IKeyTestClass>).Returns(x => KeyTestClass.Equals(item1, x.Arg<IKeyTestClass>()) (requires a static version of Equals logic extracted), and configure each substitute with this call.
Another option to consider is to use the real KeyTestClass here (or a hand-coded test double) if at all possible. Equality can be a bit tricky in .NET due to the fallback to Object.Equals for everything, so a bit of care is needed stubbing this out when equality is a key part of the contract.

Related

How to implement multiple GetHashCode methods?

I have an interface which defines a composite key:
public interface IKey : IEquatable<IKey>
{
public bool KeyPart1 { get; }
public uint KeyPart2 { get; }
int GetHashCode(); // never gets called
}
I have an object (with an ID) to which I want to add the composite key interface:
public class MyObject: IEquatable<MyObject>, IKey
{
public MyObject(int i, (bool keyPart1, uint keyPart2) key) {
{
Id=i;
KeyPart1 = key.keyPart1;
KeyPart2 = key.keyPart2;
}
public int Id { get; }
public bool KeyPart1 { get; }
public uint KeyPart2 { get; }
public bool Equals(MyObject other) => this.Id == other.Id;
public override bool Equals(object other) => other is MyObject o && Equals(o);
public override int GetHashCode() => Id.GetHashCode();
bool IEquatable<IKey>.Equals(IKey other) => this.KeyPart1 == other.KeyPart1
&& this.KeyPart2 == other.KeyPart2;
int IKey.GetHashCode() => (KeyPart1, KeyPart2).GetHashCode(); // never gets called
}
However, when have a list of these objects and try to group them using the interface, the grouping fails:
var one = new MyObject(1, (true, 1));
var two = new MyObject(2, (true, 1));
var three = new MyObject(1, (false, 0));
var items = new[] { one, two, three };
var byId = items.GroupBy(i => i);
// result: { [one, three] }, { [two] } -- as expected
var byKey = items.GroupBy<MyObject, IKey>(i => i as IKey);
// result: { [one, two, three] } // not grouped (by 'id' or 'key')
// expected: { [one, two] }, { [three] }
I'd expected that byId would have the items grouped by the Id property, and byKey would have the items grouped by the Key property.
However, byKey is not grouped at all. It appears that the override GetHashCode() method is always used rather than the explicitly implemented interface method.
Is it possible to implement something like this, where the type of the item being grouped determines the hash method to use (avoiding an EqualityComparer)?
I noticed this problem when passing the cast objects to another method expecting an IEnumerable<IKey>. I have a few different types implementing IKey and those with an existing GetHashCode() method did not work, while the others did.
Please note the objects have been simplified here and that I cannot easily change the interfaces (e.g. to use ValueTuple instead).
The GetHashCode() used in equality is either:
the one defined via object.GetHashCode(), if no equality comparer is provided
IEqualityComparer<T>.GetHashCode(T), if an equality comparer is provided
Adding your own GetHashCode() method on your own interface does nothing, and it will never be used, as it is not part of an API that the framework/library code knows about.
So, I'd forget about IKey.GetHashCode(), and either (or both):
make MyObject.GetHashCode() provide the functionality you need, or
provide a custom equality comparer separately to the MyObject instance
There are overloads of GroupBy that accept an IEqualityComparer<TKey>, for the second option.

How can I use a dynamic to find out when a property is used?

I would like to find out which of the properties in a source input object, a method has used. After executing the method I need to store in a database which of the properties was used.
The input could be any class with simple types, like this:
public class MyData : IMyData
{
public string A { get; set; }
public int B { get; set; }
public decimal C { get; set; }
}
I thought it could be done using an interface as input to the method, so I can replace the original object with a more advanced object, which stores usage of properties
public interface IMyData
{
string A { get; }
int B { get; }
decimal C { get; }
}
I can then
Create a dynamic object with the same properties
Use ImpromptuInterface to simulate the dynamic object implements my interface
Call my method with this dynamic interface
private static void Main()
{
var data = new MyData { A = "Test", B = 3, C = new decimal(1.2) };
IDictionary<string, object> replacementObject = new ExpandoObject();
replacementObject.Add("FieldsUsed", new List<string>());
foreach (var property in data.GetType().GetProperties())
replacementObject.Add(property.Name, property.GetValue(data));
var replacementInterface = replacementObject.ActLike<IMyData>();
DoStuff(replacementInterface);
Console.WriteLine($"The method used these fields {string.Join(", ", (List<string>)replacementObject["FieldsUsed"])}");
}
private static void DoStuff(IMyData source)
{
Console.WriteLine($"A is {source.A}");
if (source.B > 5)
Console.WriteLine($"C is {source.C}");
}
In the above example I would like to store that fields A and B have been used.
Only I am stuck at how I should store when a property is used by my DoStuff method.
You can write a wrapper like this:
public class ClassWrapper<T>: DynamicObject where T:class
{
private readonly T _obj;
private readonly List<string> _fieldsUsed=new List<string>();
public ClassWrapper(T obj)
{
_obj = obj;
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
PropertyInfo propertyInfo = _obj.GetType().GetProperty(binder.Name);
_fieldsUsed.Add(binder.Name);
result = propertyInfo.GetValue(_obj);
return true;
}
public List<string> GetFieldsUsed() => _fieldsUsed;
public T GetWrapper()
{
return this.ActLike<T>();
}
}
and use it like
var data = new MyData { A = "Test", B = 3, C = new decimal(1.2) };
var mc=new ClassWrapper<IMyData>(data);
IMyData wrapped = mc.GetWrapper();
DoStuff(wrapped);
Console.WriteLine($"The method used these fields {string.Join(", ", (List<string>)mc.GetFieldsUsed())}");
If you want to know when a property is used, a Interface like INotifyPropertyChanged can do that for you at runtime. The exampel is only about notification for writes (that actually changed a value), but it would be trivial to expand it to reads and writes. It is not a perfect thing of course, as different executions might follow different code paths that use different properties.
If a function takes a specific type as input, you have to asume that all properties may be relevant. This is especially true for abstract types and interfaces - often the interface exists for this function. If it is one of those two, you can also always provide your own implementation of those Interfaces and Abstract class.
I can not shake the feeling that this is a XY problem.

Setting up a simple iequatable class c#

Cant find a simple answer. My problem is I am trying to compare the VALUE of an object in a list to the VALUE of an object...
my class:
public class MatchList
{
public int SomeInt { get; set; }
public decimal SomeDecimal { get; set; }
}
I create theMatchList. It seems that I can only compare the object and not the values for object with 'theMatchList.Contains...'
MatchList ML = new MatchList();
ML.SomeInt = 12;
ML.SomeDecimal = 2.3;
if (theMatchlist.Contains(ML))
{
DoSomething;
}
How do get to fire 'DoSomething'? Assuming that there is an entry in 'theMatchList' where the values equal 12 and 2.3 respectively. I know it has something to do with iequatable, but I dont quite understand how that works. Thanks in advance!
Your naming is a bit unclear, I assume that you actually have a List<MatchList> that you want to find a particular MatchList in (I suggest renaming MatchList to at least MatchItem in that case and preferable something more descriptive).
Then from the documentation of List<T>.Contains:
This method determines equality by using the default equality comparer, as defined by the object's implementation of the IEquatable<T>.Equals method for T (the type of values in the list).
So you will have to implement IEquatable<T> for your class. In addition, the advice is that
[i]f you implement Equals, you should also override the base class implementations of Object.Equals(Object) and GetHashCode so that their behavior is consistent with that of the IEquatable.Equals method.
If you implement GetHashCode, its result should not change over the lifetime of your object. In most cases, making the class immutable is sufficient. If you need to be able to update the fields, you need to implement GetHashCode differently.
So all in all, if you want to use Contains your class will end up looking something like below:
public class MatchList : IEquatable<MatchList>
{
// Note: Fields are readonly to satisfy GetHashCode contract
private readonly int someInt;
private readonly decimal someDecimal;
// Public constructor creates immutable object
public MatchList(int myInt, decimal myDecimal)
{
this.someInt = myInt;
this.myDecimal = myDecimal;
}
// Properties are now read-only too.
public int SomeInt { get { return this.someInt; } }
public decimal SomeDecimal { get { return this.someDecimal; } }
// Implementation of IEquatable<MatchList>
public bool Equals( MatchList other )
{
return (other != null)
&& (this.SomeInt == other.SomeInt)
&& (this.SomeDecimal == other.SomeDecimal);
}
// Override of Object.Equals
// Calls the IEquatable.Equals version if possible.
public override bool Equals( object obj )
{
return (obj is MatchList) && this.Equals(obj as MatchList);
}
public override int GetHashCode()
{
return (this.someInt * 17) ^ this.someDecimal.GetHashCode();
}
}
As I commented, your question is pretty unclear so I'll do my best to explain the concept.
It's pretty likely what you were trying to code is the items in the list not the list itself:
public class MatchItem : IEquatable<MatchItem>
{
public int SomeInt { get; set; }
public decimal SomeDecimal {get; set; }
public bool Equals(MatchItem item)
{
if(item == null)
return false;
return this.SomeInt == item.SomeInt && this.SomeDecimal == item.SomeDecimal;
}
// You should also override object.ToString, object.Equals & object.GetHashCode.
// Omitted for brevity here!
}
You'll note that has an implementation of IEquatable<MatchItem> which allows it to be compared to other instances of MatchItem.
Thereafter, this code will work:
var items = new List<MatchItem>()
{
new MatchItem{SomeInt = 1, SomeDecimal = 0.3M},
new MatchItem{SomeInt = 12, SomeDecimal = 2.3M}
};
var searchItem = new MatchItem{SomeInt = 1, SomeDecimal = 0.3M};
Console.WriteLine(items.Contains(searchItem)); // true
Working example: http://rextester.com/ZWNC6890

JSON.NET Serialization - How does DefaultReferenceResolver compare equality?

I am using JSON.NET 6.0.3. I have changed PreserveReferences option as follows:
HttpConfiguration.Formatters.JsonFormatter.SerializerSettings.PreserveReferencesHandling = PreserveReferencesHandling.Objects;
My object graph resembles the following:
public class CarFromManufacturer
{
public int CarID { get; set; }
public string Make { get; set; }
public string Model { get; set; }
public CarManufacturer Manufacturer { get; set; }
}
public class CarManufacturer
{
public int ManufacturerID { get; set; }
public string Name { get; set; }
}
My WebAPI controller is returning the result set of IEnumerable[CarFromManufacturer]. So the result could be a list of 5 cars from two unique manufacturer objects. I am expecting the JSON result to list each manufacturer only once fully serialized and then subsequent uses of the same Manufacturer to be $ref ID to the original's $id. That is not happening.
Even though I can't find a single piece of documentation that speaks about how equality is established for the ReferenceResolver, I've implemented IEquatable<CarManufacturer> along with override of base.Equals and base.GetHashCode() with no luck.
I'd like to avoid implementing my own IReferenceResolver because have very similar object graphs working as expected in the same project.
The only thing I can think of is that I am using factory objects and instead of creating each unique CarManufacturer first, then creating the instances of CarFromManufacturer passing in CarManufacturer... i am creating a new instance of the CarManufacturer. This would explain why the objects aren't equal, but that's why I implemented IEquatable and overrides of base.Equals(object) and base.GetHashCode().
I've looked into the source for DefaultReferenceResolver and it uses the default constructor of BidirectionalDictionary which uses EqualityComparer<T>.Default which, from MSDN documentation, uses the T's implementation of IEquatable<T> if it exists, or otherwise uses T's base.Equals() implementation.... all of this would lead me to believe that IEquatable in CarManufacturer should fix my problem. However, placing breakpoints in CarManufacturer.Equals() and GethashCode() never hit..
JSON.NET's logic for resolving references by default just compares references using this comparer.
If you want to compare objects in a different manner, you'll have to implement a custom IReferenceResolver.
Here's an example that takes an IEqualityComparer<T> to accommodate your use case:
public class ReferenceResolver<T> : IReferenceResolver
{
private Dictionary<string, T> stringToReference;
private Dictionary<T, string> referenceToString;
private int referenceCount;
public ReferenceResolver(IEqualityComparer<T> comparer)
{
this.stringToReference = new Dictionary<string, T>();
this.referenceToString = new Dictionary<T, string>(comparer);
this.referenceCount = 0;
}
public void AddReference(
object context,
string reference,
object value)
{
this.referenceToString.Add((T)value, reference);
this.stringToReference.Add(reference, (T)value);
}
public string GetReference(
object context,
object value)
{
string result = null;
if (!this.referenceToString.TryGetValue((T)value, out result))
{
referenceCount++;
result = referenceCount.ToString(CultureInfo.InvariantCulture);
this.referenceToString.Add((T)value, result);
this.stringToReference.Add(result, (T)value);
}
return result;
}
public bool IsReferenced(
object context,
object value)
{
return this.referenceToString.ContainsKey((T)value);
}
public object ResolveReference(
object context,
string reference)
{
T r = default(T);
this.stringToReference.TryGetValue(reference, out r);
return r;
}
}
Json.Net will call the Equals method on the objects being compared. In certain scenarios you may not want this however for example when it is checking for circular references it does the same whereas it may be more ideal to check for reference equality. They do this however to give the developer full control by overridding the Equals method in their classes.
You can override the default implementation. For example to make this a reference equality you would do the following:
var settings = new JsonSerializerSettings
{
EqualityComparer = new DefaultEqualityComparer(),
};
public class DefaultEqualityComparer : IEqualityComparer
{
public bool Equals(object x, object y)
{
return ReferenceEquals(x, y);
}
public int GetHashCode(object obj)
{
return obj.GetHashCode();
}
}

Mono implementation of Dictionary<T,T> using .Equals(obj o) instead of .GetHashCode()

By searching though msdn c# documentation and stack overflow, I get the clear impression that Dictionary<T,T> is supposed to use GetHashCode() for checking key-uniqueness and to do look-up.
The Dictionary generic class provides a mapping from a set of keys to a set of values. Each addition to the dictionary consists of a value and its associated key. Retrieving a value by using its key is very fast, close to O(1), because the Dictionary class is implemented as a hash table.
...
The speed of retrieval depends on the quality of the hashing algorithm of the type specified for TKey.
I Use mono (in Unity3D), and after getting some weird results in my work, I conducted this experiment:
public class DictionaryTest
{
public static void TestKeyUniqueness()
{
//Test a dictionary of type1
Dictionary<KeyType1, string> dictionaryType1 = new Dictionary<KeyType1, string>();
dictionaryType1[new KeyType1(1)] = "Val1";
if(dictionaryType1.ContainsKey(new KeyType1(1)))
{
Debug.Log ("Key in dicType1 was already present"); //This line does NOT print
}
//Test a dictionary of type1
Dictionary<KeyType2, string> dictionaryType2 = new Dictionary<KeyType2, string>();
dictionaryType2[new KeyType2(1)] = "Val1";
if(dictionaryType2.ContainsKey(new KeyType2(1)))
{
Debug.Log ("Key in dicType2 was already present"); // Only this line prints
}
}
}
//This type implements only GetHashCode()
public class KeyType1
{
private int var1;
public KeyType1(int v1)
{
var1 = v1;
}
public override int GetHashCode ()
{
return var1;
}
}
//This type implements both GetHashCode() and Equals(obj), where Equals uses the hashcode.
public class KeyType2
{
private int var1;
public KeyType2(int v1)
{
var1 = v1;
}
public override int GetHashCode ()
{
return var1;
}
public override bool Equals (object obj)
{
return GetHashCode() == obj.GetHashCode();
}
}
Only the when using type KeyType2 are the keys considered equal. To me this demonstrates that Dictionary uses Equals(obj) - and not GetHashCode().
Can someone reproduce this, and help me interpret the meaning is? Is it an incorrect implementation in mono? Or have I misunderstood something.
i get the clear impression that Dictionary is supposed to use
.GetHashCode() for checking key-uniqueness
What made you think that? GetHashCode doesn't return unique values.
And MSDN clearly says:
Dictionary requires an equality implementation to
determine whether keys are equal. You can specify an implementation of
the IEqualityComparer generic interface by using a constructor that
accepts a comparer parameter; if you do not specify an implementation,
the default generic equality comparer EqualityComparer.Default is
used. If type TKey implements the System.IEquatable generic
interface, the default equality comparer uses that implementation.
Doing this:
public override bool Equals (object obj)
{
return GetHashCode() == obj.GetHashCode();
}
is wrong in the general case because you might end up with KeyType2 instances that are equal to StringBuilder, SomeOtherClass, AnythingYouCanImagine and what not instances.
You should totally do it like so:
public override bool Equals (object obj)
{
if (obj is KeyType2) {
return (obj as KeyType2).var1 == this.var1;
} else
return false;
}
When you are trying to override Equals and inherently GetHashCode you must ensure the following points (given the class MyObject) in this order (you were doing it the other way around):
1) When are 2 instances of MyObject equal ? Say you have:
public class MyObject {
public string Name { get; set; }
public string Address { get; set; }
public int Age { get; set; }
public DateTime TimeWhenIBroughtThisInstanceFromTheDatabase { get; set; }
}
And you have 1 record in some database that you need to be mapped to an instance of this class.
And you make the convention that the time you read the record from the database will be stored
in the TimeWhenIBroughtThisInstanceFromTheDatabase:
MyObject obj1 = DbHelper.ReadFromDatabase( ...some params...);
// you do that at 14:05 and thusly the TimeWhenIBroughtThisInstanceFromTheDatabase
// will be assigned accordingly
// later.. at 14:07 you read the same record into a different instance of MyClass
MyObject obj2 = DbHelper.ReadFromDatabase( ...some params...);
// (the same)
// At 14:09 you ask yourself if the 2 instances are the same
bool theyAre = obj1.Equals(obj2)
Do you want the result to be true ? I would say you do.
Therefore the overriding of Equals should like so:
public class MyObject {
...
public override bool Equals(object obj) {
if (obj is MyObject) {
var that = obj as MyObject;
return (this.Name == that.Name) &&
(this.Address == that.Address) &&
(this.Age == that.Age);
// without the syntactically possible but logically challenged:
// && (this.TimeWhenIBroughtThisInstanceFromTheDatabase ==
// that.TimeWhenIBroughtThisInstanceFromTheDatabase)
} else
return false;
}
...
}
2) ENSURE THAT whenever 2 instances are equal (as indicated by the Equals method you implement)
their GetHashCode results will be identitcal.
int hash1 = obj1.GetHashCode();
int hash2 = obj2.GetHashCode();
bool theseMustBeAlso = hash1 == hash2;
The easiest way to do that is (in the sample scenario):
public class MyObject {
...
public override int GetHashCode() {
int result;
result = ((this.Name != null) ? this.Name.GetHashCode() : 0) ^
((this.Address != null) ? this.Address.GetHashCode() : 0) ^
this.Age.GetHashCode();
// without the syntactically possible but logically challenged:
// ^ this.TimeWhenIBroughtThisInstanceFromTheDatabase.GetHashCode()
}
...
}
Note that:
- Strings can be null and that .GetHashCode() might fail with NullReferenceException.
- I used ^ (XOR). You can use whatever you want as long as the golden rule (number 2) is respected.
- x ^ 0 == x (for whatever x)

Categories

Resources