I'm trying to compare objects within two different Dictionary<string,object>
(to find differences in a versioned repository.
The dictionary can contains any serialize type, either value-type or reference-type.
I loop on all keys to perform the comparison. Because of the value type boxing, I implemented a small utility method found on SO :
private static bool AreValueEquals(object o1, object o2)
{
return (o1 != null && o1.GetType().IsValueType)
? o1.Equals(o2)
: o1 == o2;
}
This method is used in my main method like this:
private static List<string> GetDifferent(Dictionary<string, object> currentValues, Dictionary<string, object> previousValues)
{
var changed = from fieldName in currentValues.Keys.Union(previousValues.Keys).Distinct()
let currentVal = GetIfExists(currentValues, fieldName)
let previousVal = GetIfExists(previousValues, fieldName)
where !AreValueEquals(currentVal, previousVal)
select fieldName;
return changed.ToList();
}
private static object GetIfExists(Dictionary<string, object> values, string fieldName)
{
return values.ContainsKey(fieldName) ? values[fieldName] : null;
}
While the AreValueEquals
method works as expected on my test case (dotnetfiddle) , at runtime , I get unexpected result:
I don't understand this result. Is my implementation correct? How to fix?
String
is a reference type.
I don't know how you are creating those strings but they a re probably represented as 2 different instances of string object.
In you method you aare doing a ==
on 2 objects. This will by default check only if they are the same references.
Why not use Generics and use the Comparer.Default or just use the Equals() with a null check considering your are boxing?
object a = "d";
object b = new String(new []{'d'});
Console.Write("a == b: ");
Console.WriteLine(a == b);
Console.WriteLine("AreValueEquals: " + AreValueEquals(a,b));
Console.WriteLine("Equals: " + a.Equals(b));
Gives:
a == b: False
AreValueEquals: False
Equals: True
Confirming the intern:
Console.WriteLine("\r\nComparing 2 constants\r\n");
object c = "d";
Console.Write("a == c: ");
Console.WriteLine(a == c);
Console.WriteLine("AreValueEquals: " + AreValueEquals(a,c));
Console.WriteLine("Equals: " + a.Equals(c));
Gives:
Comparing 2 constants
a == c: True
AreValueEquals: True
Equals: True
Have a look at this fiddle
I've changed the GetDifferent method to what I think you are after:
private static List<string> GetDifferent(Dictionary<string, object> currentValues, Dictionary<string, object> previousValues)
{
var changed = currentValues
.Where(k => previousValues.Any(p => p.Key == k.Key && !AreValueEquals(k.Value, p.Value)))
.Select(k => k.Key);
return changed.ToList();
}
See this fiddle: https://dotnetfiddle.net/JZ6v6a
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.