Beruflich Dokumente
Kultur Dokumente
{
#region ToString
public override string ToString()
{
return ToString(AsDictionary());
}
private static string ToString(object
{
if (value == null)
{
return "null";
}
if (value is String)
{
return '"' + (String) value +
}
if (value is IDictionary)
{
return ToString((IDictionary)
}
if (value is IEnumerable)
{
return ToString((IEnumerable)
}
return value.ToString();
}
value)
'"';
value);
value);
#region Equality
public override int GetHashCode()
{
return GetHashCodeDico(AsDictionary());
}
private static int GetHashCodeObject(object obj)
{
if (obj == null)
{
return 0;
}
if (obj is IDictionary)
{
return GetHashCodeDico((IDictionary)obj);
}
if (obj is IEnumerable)
{
return GetHashCodeCollection((IEnumerable) obj);
}
return obj.GetHashCode();
}
private static int GetHashCodeCollection(IEnumerable items)
{
var result = 0;
foreach (var item in items)
{
result = (result * 397) ^ GetHashCodeObject(item);
}
return result;
}
public static int GetHashCodeDico(IDictionary dico)
{
var result = 0;
foreach (var key in dico.Keys)
{
result = (result * 397) ^ GetHashCodeObject(key);
result = (result * 397) ^ GetHashCodeObject(dico[key]);
}
return result;
}
public override bool Equals(object obj)
{
return EqualsObject(this, obj);
}
private static bool EqualsObject(object obj1, object obj2)
{
if (obj1 == obj2)
{
return true;
}
if (obj1 == null || obj2 == null)
{
return false;
}
if (obj1 is IDictionary && obj2 is IDictionary)
{
return EqualsDico((IDictionary) obj1, (IDictionary) obj2);
}
if (obj1 is IEnumerable && obj2 is IEnumerable)
{
return EqualsCollection((IEnumerable)obj1, (IEnumerable)obj2);
}
if (obj1.GetType() != obj2.GetType())
{
return false;
}
if (obj1 is ValueObject)
{
return EqualsValue((ValueObject)obj1, (ValueObject)obj2);
}
return Equals(obj1, obj2);
}
private static bool EqualsCollection(IEnumerable items1, IEnumerable ite
ms2)
{
var list1 = new List<Object>(items1.Cast<Object>());
var list2 = new List<Object>(items2.Cast<Object>());
if (list1.Count != list2.Count)
{
return false;
}
for (int i = 0; i < list1.Count; i++)
{
if (!Equals(list1[i], list2[i]))
{
return false;
}
}
return true;
}
private static bool EqualsValue(ValueObject obj1, ValueObject obj2)
{
return EqualsDico(obj1.AsDictionary(), obj2.AsDictionary());
}
public static bool EqualsDico(IDictionary dico1, IDictionary dico2)
{
if (dico1.Count != dico2.Count)
{
return false;
}
foreach (var key in dico1.Keys)
{
if (!dico2.Contains(key))
{
return false;
}
if (!EqualsObject(dico1[key], dico2[key]))
{
return false;
}
}
return true;
}
#endregion
#region implementation
private Dictionary<string, object> AsDictionary()
{
return FieldInfos(GetType()).Distinct()
.ToDictionary(field => field.Name, field => field.GetValue(this)
);
}
private IEnumerable<FieldInfo> FieldInfos(Type type)
{
if (type == null)
{
return new FieldInfo[0];
}
return FieldInfos(type.BaseType)
.Concat(type.GetFields(BindingFlags.Instance | BindingFlags.Publ
ic | BindingFlags.NonPublic));
}
#endregion
}
[TestFixture]
public class FavouriteObjectTest
{
#region Test classes
internal class Identity : ValueObject
{
private readonly string _name;
private readonly int _age;
private readonly IEnumerable<string> _cars;
private readonly Dictionary<string, int> _childrenAges;
internal Identity(string name, int age, IEnumerable<string> cars, Di
ctionary<string, int> childrenAges)
{
_name = name;
_age = age;
_cars = cars;
_childrenAges = childrenAges;
}
public Dictionary<string, int> ChildrenAges { get { return _children
Ages; } }
public IEnumerable<string> Cars { get { return _cars; } }
public int Age { get { return _age; } }
public string Name { get { return _name; } }
}
{
AssertEquals(new IdentityBuilder(), new IdentityBuilder(), "identica
l instances");
AssertEquals(new IdentityBuilder(), new IdentityBuilder { Cars = new
List<string>(new IdentityBuilder().Cars) }, "identical instances but with diffe
rent type of collection");
Assert.AreNotEqual(new IdentityBuilder().Build(), null, "null and re
al instances");
AssertNotEquals(new IdentityBuilder(), new IdentityBuilder().Tap(x =
> x.Name = "Bob"), "different instances by string field");
AssertNotEquals(new IdentityBuilder(), new IdentityBuilder().Tap(x =
> x.Age = 1), "different instances by int field");
AssertNotEquals(new IdentityBuilder(), new IdentityBuilder().Tap(x =
> x.Cars = new[] { "Deloreal" }), "different instances by collection field");
AssertNotEquals(new IdentityBuilder(), new IdentityBuilder().Tap(x =
> x.ChildrenAges["Junior"] = 11), "different instances by dictionary value field
");
AssertNotEquals(new IdentityBuilder(), new IdentityBuilder().Tap(x =
> x.ChildrenAges["Rex"] = 3), "different instances by dictionary key field");
}
[Test]
public void EqualityWorksEvenWithDerivedClasses()
{
Assert.AreEqual(new USIdentity("Toto"), new USIdentity("Toto"), "Ide
ntical sub instances");
Assert.AreNotEqual(new USIdentity("Toto"), new USIdentity("Gyzmo"),
"Different sub instances");
Assert.AreNotEqual(new USIdentity("Toto"), new CCCPIdentity("Toto"),
"Identical sub instances of different classes");
}
private static void AssertNotEquals(Identity expected, Identity actual,
string failMessage)
{
Assert.AreNotEqual(expected, actual, failMessage);
Assert.AreNotEqual(expected.GetHashCode(), actual.GetHashCode(), fai
lMessage);
}
private static void AssertEquals(Identity expected, Identity actual, str
ing failMessage)
{
Assert.AreEqual(expected, actual, failMessage);
Assert.AreEqual(expected.GetHashCode(), actual.GetHashCode(), "Hash
code of " + failMessage);
}
}