Sie sind auf Seite 1von 6

public class FavouriteObject

{
#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);

private static string ToString(IDictionary dictionary)


{
return BuildString(dictionary.Keys, '{',
key => String.Format("{0} -> {1}", ToString(key),
ToString(dictionary[key])), '}');
}
private static string ToString(IEnumerable items)
{
return BuildString(items, '[', ToString, ']');
}
private static string BuildString(IEnumerable items, char prefix, Func<o
bject, string> toString, char suffix)
{
var result = new StringBuilder();
result.Append(prefix);
var first = true;
foreach (var item in items)
{
if (!first)
{
result.Append(", ");
}
first = false;
result.Append(toString(item));
}
result.Append(suffix);
return result.ToString();
}
#endregion

#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; } }
}

internal class IdentityBuilder : RefBuilder<Identity>


{
internal string Name = "John";
internal int Age = 42;
internal IEnumerable<string> Cars = new[] { "Pontiac", "Pacer" };
internal Dictionary<string, int> ChildrenAges = new Dictionary<strin
g, int>
{
{"James", 12},
{"Junior", 6}
};
protected override Identity DoBuild()
{
return new Identity(Name, Age, Cars, ChildrenAges);
}
}
internal class USIdentity : Identity
{
internal USIdentity(string name)
: base(name, 0, null, null)
{
}
}
internal class CCCPIdentity : Identity
{
internal CCCPIdentity(string name)
: base(name, 0, null, null)
{
}
}
#endregion
[Test]
public void AutomaticalyImplementsToString()
{
var id = new IdentityBuilder().Build();
Assert.That(id.ToString(), Is.StringContaining("\"_name\" -> \"John\
""), "Id to string");
Assert.That(id.ToString(), Is.StringContaining("\"_age\" -> 42"), "I
d to string");
Assert.That(id.ToString(), Is.StringContaining("\"_cars\" -> [\"Pont
iac\", \"Pacer\"]"), "Id to string");
Assert.That(id.ToString(), Is.StringContaining("\"_childrenAges\" ->
{\"James\" -> 12, \"Junior\" -> 6}"), "Id to string");
}
[Test]
public void StringHandlesNullFields()
{
var id = new Identity(null, 0, null, null);
Assert.That(id.ToString(), Is.StringContaining("\"_name\" -> null"),
"Id to string");
}
[Test]
public void AutomaticalyImplementsEquality()

{
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);
}
}

Das könnte Ihnen auch gefallen