What I've read on the HashSet is it uses the default comparer for a class. I'm expecting the code below to fail when adding the second Spork to the hash set. I think my understanding of what is happening is incomplete. From MSDN of the HashSet constructor:
The IEqualityComparer implementation to use when comparing values in the set, or null to use the default EqualityComparer implementation for the set type.
So what is the default comparer, and how can I tell .Net to use my own comparer?
public class Spork : IEquatable<Spork>
{
public int Id { get; set; }
public bool Equals(Spork other)
{
return other != null && other.Id == this.Id;
}
public override bool Equals(object obj)
{
var other = obj as Spork;
return other != null && other.Id == this.Id;
}
public override int GetHashCode()
{
return Id.GetHashCode();
}
}
public class Bjork
{
public static HashSet<Spork> Sporks { get; set; }
public static void Main()
{
Sporks = new HashSet<Spork>();
Sporks.Add(new Spork() { Id = 0 });
Sporks.Add(new Spork() { Id = 0 }); // come on, please throw an exception
}
}
It is using your equality methods - but HashSet<T>.Add doesn't throw an exception when you try to add an equal value - it just returns false.
If you change the last two lines to print out the return value of Add, you'll see it returns True the first time, then False.
If your goal is to work like the Dictionary and disallow the same entry multiple times and throw an exception, you would have to inherit from HashSet and IEquatable:
class UniqueHashSet<T> : HashSet<T>, IEquatable<T>
Then, of course, write a new .Add() method to hide the base Add.
But, I'm sure there is a better way.
Or, as #Jon says, it does maintain a unique collection.
Related
As part of a website I'm working on, users may need to update partial information for each ticket submitted. When I test out a TryUpdateModel with this particular class which has an explicit operator to convert it to a string, I get an InvalidCastException. I've managed to isolate this exception down from all the previous MVC code to this:
Class
public class ConversionOperator
{
public ConversionOperator()
{
FullName = string.Empty;
}
public ConversionOperator(string fullName)
{
FullName = fullName;
}
public string FullName { get; set; }
public static explicit operator string(ConversionOperator item)
{
return item == null
? string.Empty
: item.FullName;
}
public static explicit operator ConversionOperator(string item)
{
return string.IsNullOrEmpty(item)
? new ConversionOperator()
: new ConversionOperator(item);
}
public override bool Equals(object obj)
{
if (obj == null)
{
return false;
}
ConversionOperator other = (ConversionOperator) obj;
return FullName == other.FullName;
}
}
Unit Test
[TestMethod]
public void Verify_Conversion_To_String()
{
ConversionOperator first;
first = new ConversionOperator("Henry Beauford Autumnbottom Elderberry McClatchen");
Assert.AreEqual(first.FullName, (string) first); // passes
Assert.IsTrue(first.Equals("Henry Beauford Autumnbottom Elderberry McClatchen")); // throws exception
}
[TestMethod]
public void Verify_Conversion_From_String()
{
string name = "Henry Beauford Autumnbottom Elderberry McClatchen";
Assert.AreEqual((ConversionOperator) name, new ConversionOperator(name));
}
The first Assert in Verify_Conversion_To_String passes, but the second one fails, throwing an InvalidCastException. It's clear that the .NET Framework knows obj is a string, but the explicit conversion isn't being called.
Changing from a cast to as ConversionOperator produces a null object, which isn't correct either.
It looks like you are passing in a String to your Equals method. If that's the case then it will fail the cast to ProperName.
What you will can do is create a different Equals method that takes a string (or several strings) and tests those against the ProperName properties to see if they'd match:
public bool Equals(string fullName, t1 middleNameOptions, t2 displayOptions)
{
return this.FullName == item.FullName
&& this.MiddleNameOptions == item.MiddleNameOptions
&& this.DisplayOptions == item.DisplayOptions;
}
I solved the problem by implementing IEquatable<string>:
public bool Equals(string other)
{
ConversionOperator item = new ConversionOperator(other);
return this.Equals(item);
}
Now the unit tests pass, and I'm going to go bang my head on the wall until I forget that I asked this question.
To prevent the exception from occurring, you can call the object's ToString() method:
public override bool Equals(object obj)
{
if (obj == null)
{
return false;
}
ProperName item = (ConversionOperator) obj.ToString();
return FullName == item.FullName
&& MiddleNameOptions == item.MiddleNameOptions
&& DisplayOptions == item.DisplayOptions;
}
Notes:
In order for the TryUpdateModel method to bind a model to the given prefix (of form data), you will likely need an implicit cast.
If you look at the source for the Controller class, can see that under the hood, the DefaultModelBinder is used.
The DefaultModelBinder has limitations, and is generally better with a specialized model, which is then mapped to your domain model (perhaps with manually written code, or with AutoMapper)
If you can't change your approach, then I suggest creating a Custom Model Binder which will give you direct control of how the form is translated to the model.
Please explain the technique used in this code to test Object Equality and Identity.
Better, if you can supply me any web-link/book-reference for detailed discussion.
[Serializable]
public abstract class BusinessObject<T> : IBusinessObject where T : BusinessObject<T>
{
private int? requestedHashCode;
public virtual int ID { get; set; }
public virtual bool Equals(IBusinessObject other)
{
if (null == other || !GetType().IsInstanceOfType(other))
{
return false;
}
if (ReferenceEquals(this, other))
{
return true;
}
bool otherIsTransient = Equals(other.ID, default(T));
bool thisIsTransient = IsTransient();
if (otherIsTransient && thisIsTransient)
{
return ReferenceEquals(other, this);
}
return other.ID.Equals(ID);
}
protected bool IsTransient()
{
return Equals(ID, default(T));
}
public override bool Equals(object obj)
{
var that = obj as IBusinessObject;
return Equals(that);
}
public override int GetHashCode()
{
if (!requestedHashCode.HasValue)
{
requestedHashCode = IsTransient() ? base.GetHashCode() : ID.GetHashCode();
}
return requestedHashCode.Value;
}
}
What is a transient object?
it first checks if other is an instance of the same type as the current object. If not, they're not equal
it then performs a reference equality to check if other and the current object are the same instance. If they are, obviously they are equal
If both other and the current object are transient (i.e. not yet persisted), they don't have an ID, so they can't be compared by ID. Instead, they are compared by reference. (as noted by Marc Gravell in the comments, the test to check if the object is transient is broken; it doesn't make sense to compare an int to default(T))
Eventually, their IDs are compared; the objects are considered equal if they have the same ID
I think what the code is trying to do is say "has it got an ID yet", i.e. a "transient" object might (if I read the code's intent correctly) be one that is not yet saved to the DB. Then equality is defined as:
if it has an ID, does it match? (even for different instances of the same type)
if it doesn't have an ID, is it the same object instance (reference)
unfortunately the implementation looks completely broken, as Equals(ID, default(T)) is meaningless when T is something completely different (a BusinessObject<T>) - hence default(T) will always be null and ID will never be null (it is not nullable). So nothing will ever report as transient.
Additionally, this code:
if (null == other || !GetType().IsInstanceOfType(other))
is hugely inefficient. I suspect something involving as would be far preferable, but again: the code looks so... tortured... that I'm loathe to second-guess the intent.
I have a class it contains some string members, some double members and some array objects.
I create two objects of this class, is there any simplest, efficient way of comparing these objects and say their equal? Any suggestions?
I know how to write a compare function, but will it be time consuming.
The only way you can really do this is to override bool Object.Equals(object other) to return true when your conditions for equality are met, and return false otherwise. You must also override int Object.GetHashCode() to return an int computed from all of the data that you consider when overriding Equals().
As an aside, note that the contract for GetHashCode() specifies that the return value must be equal for two objects when Equals() would return true when comparing them. This means that return 0; is a valid implementation of GetHashCode() but it will cause inefficiencies when objects of your class are used as dictionary keys, or stored in a HashSet<T>.
The way I implement equality is like this:
public class Foo : IEquatable<Foo>
{
public bool Equals(Foo other)
{
if (other == null)
return false;
if (other == this)
return true; // Same object reference.
// Compare this to other and return true/false as appropriate.
}
public override bool Equals(Object other)
{
return Equals(other as Foo);
}
public override int GetHashCode()
{
// Compute and return hash code.
}
}
A simple way of implementing GetHashCode() is to XOR together the hash codes of all of the data you consider for equality in Equals(). So if, for example, the properties you compare for equality are string FirstName; string LastName; int Id;, your implementation might look like:
public override int GetHashCode()
{
return (FirstName != null ? FirstName.GetHashCode() : 0) ^
(LastName != null ? LastName.GetHashCode() : 0) ^
Id; // Primitives of <= 4 bytes are their own hash codes
}
I typically do not override the equality operators, as most of the time I'm concerned with equality only for the purposes of dictionary keys or collections. I would only consider overriding the equality operators if you are likely to do more comparisons by value than by reference, as it is syntactically less verbose. However, you have to remember to change all places where you use == or != on your object (including in your implementation of Equals()!) to use Object.ReferenceEquals(), or to cast both operands to object. This nasty gotcha (which can cause infinite recursion in your equality test if you are not careful) is one of the primary reasons I rarely override these operators.
The 'proper' way to do it in .NET is to implement the IEquatable interface for your class:
public class SomeClass : IEquatable<SomeClass>
{
public string Name { get; set; }
public double Value { get; set; }
public int[] NumberList { get; set; }
public bool Equals(SomeClass other)
{
// whatever your custom equality logic is
return other.Name == Name &&
other.Value == Value &&
other.NumberList == NumberList;
}
}
However, if you really want to do it right, this isn't all you should do. You should also override the Equals(object, object) and GetHashCode(object) methods so that, no matter how your calling code is comparing equality (perhaps in a Dictionary or perhaps in some loosely-typed collection), your code and not reference-type equality will be the determining factor:
public class SomeClass : IEquatable<SomeClass>
{
public string Name { get; set; }
public double Value { get; set; }
public int[] NumberList { get; set; }
/// <summary>
/// Explicitly implemented IEquatable method.
/// </summary>
public bool IEquatable<SomeClass>.Equals(SomeClass other)
{
return other.Name == Name &&
other.Value == Value &&
other.NumberList == NumberList;
}
public override bool Equals(object obj)
{
var other = obj as SomeClass;
if (other == null)
return false;
return ((IEquatable<SomeClass>)(this)).Equals(other);
}
public override int GetHashCode()
{
// Determine some consistent way of generating a hash code, such as...
return Name.GetHashCode() ^ Value.GetHashCode() ^ NumberList.GetHashCode();
}
}
Just spent the whole day writing an extension method looping through reflecting over properties of an object with various complex bits of logic to deal with different property type and actually got it close to good, then at 16:55 it dawned on me that if you serialize the two object, you simply need compare the two strings ... duh
So here is a simple serializer extension method that even works on Dictionaries
public static class TExtensions
{
public static string Serialize<T>(this T thisT)
{
var serializer = new DataContractSerializer(thisT.GetType());
using (var writer = new StringWriter())
using (var stm = new XmlTextWriter(writer))
{
serializer.WriteObject(stm, thisT);
return writer.ToString();
}
}
}
Now your test can be as simple as
Asset.AreEqual(objA.Serialise(), objB.Serialise())
Haven't done extensive testing yet, but looks promising and more importantly, simple. Either way still a useful method to have in your utility set right ?
The best answer is to implement IEquatable for your class - it may not be the answer you want to hear, but that's the best way to implement value equivalence in .NET.
Another option would be computing a unique hash of all of the members of your class and then doing value comparisons against those, but that's even more work than writing a comparison function ;)
Since these are objects my guess is that you will have to override the Equals method for objects. Otherwise the Equals method will give you ok only if both objects refering to the same object.
I know this is not the answer you want. But since there is little number of properties in your class you can easily override the method.
i need to compare two objects but compare a number of their properties in one hit.
this is not for sorting, but instead to confirm whether anything has changed; as one is the old saved instance, and the second is a newly imported instance of the same thing
i assume this is best served by writing a custom comparer. just am a bit confused as to whether to do IComparer, or IComparable, or what tbh.
thanks
nat
If you only have a single definition of equality for your class, you don't really need to implement any interface: simply override the Equalsmethod. Best practice though, would be to implement IEquatable<T>and to override GetHashCode sensibly (if you don't override the hash-code, equality will misbehave when collection classes, LINQ methods etc. use it as a pre-condition for equality). Here's a sample implementation:
public class Person : IEquatable<Person>
{
public string Name { get; set; }
public int Age { get; set; }
public override int GetHashCode()
{
return (Name == null ? 0 : Name.GetHashCode()) ^ Age;
}
public override bool Equals(object obj)
{
return Equals(obj as Person);
}
public bool Equals(Person other)
{
return other != null && other.Name == Name && other.Age == Age;
}
}
This will allow you to do:
Person savedPerson = ...
Person importedPerson = ...
bool hasChanged = !savedPerson.Equals(importedPerson);
If, on the other hand, you do have lots of different definitions of equality for different circumstances, your best bet would be to write up different IEqualityComparer<T>implementations. Here's a sample implementation:
public class AgeComparer : IEqualityComparer<Person>
{
public bool Equals(Person x, Person y)
{
return (x == null || y == null) ? x == y : x.Age == y.Age;
}
public int GetHashCode(Person obj)
{
return obj == null ? 0 : obj.Age;
}
}
In this case, the check will look like:
Person savedPerson = ...
Person importedPerson = ...
IEqualityComparer<Person> comparer = ...
bool hasChanged = !comparer.Equals(savedPerson, importedPerson);
As you have alluded to IComparable is typically used for sorting.
In this case you would want to overload the comparison operator: ==
Because the reverse comparison should also be valid, this implies you must also overload the != operator.
When you overload == and !- you are also expected to override Equals and GetHashCode.
A decent C# book should explain the details.
An alternative to implementing the IComparable interface would be to override the Equals and GetHashCode functions.
That is about how you want to perform compare operation. You can do the operation in both ways:
public void Method()
{
Foo p1 = new Foo();
Foo p2 = new Foo();
p1.CompareTo(p2);
FooComparer c = new FooComparer();
c.Compare(p1, p2);
}
class Foo : IComparable
{
public int CompareTo(object obj)
{
throw new NotImplementedException();
}
}
class FooComparer : IComparer<Foo>
{
public int Compare(Foo x, Foo y)
{
throw new NotImplementedException();
}
}
I prefer using IComparer as seperation of concerns. Foo is my class, I have some busines needs on it. If I want to compare some Foos, I use FooComparer. For your situation you can return the number of changed properties from Compare method. If Compare method return 0. Then two Foos are same.
As I said. That is completely how you want to perform the action I think. Overriding Equality Operators are also good solution. Implementing IEqualityComparer<T> is another solution.
Yes you will need your type to implement IComparable. Here is a sample on how to do it.
I'd like to know whether there is a way to compare two objects in MBUnit so that the test is passed when the objects "look" the same, even if those are distinct instances?
For example:
[TestFixture]
class ComparisonTestFixture
{
class foo
{
public string bar;
}
[Test]
public void ComparisonTest()
{
foo foo1 = new foo()
{
bar = "baz"
};
foo foo2 = new foo()
{
bar = "baz"
};
//This assertion should be successful, but it isn't
//*** Failures ***
//Expected values to be equal.
//Expected Value & Actual Value : {foo: bar = "zzz...."}
//Remark : Both values look the same when formatted but they are distinct instances.
Assert.AreEqual(foo1,foo2);
}
}
Assert.AreEqual() does not work for this (test fails, see source code above). Since it remarks that "Both values look the same when formatted but they are distinct instances", I figure there must be some way to do this built into MbUnit already without serializing the objects to XML in my own code.
Do I have to write my own Assert extension method for this?
Yann also implemented a StructuralEqualityComparer that compares property values one by one given a set of lambdas for each property. Worth looking at.
More info here: http://www.gallio.org/api/html/T_MbUnit_Framework_StructuralEqualityComparer_1.htm
There is an overload of Assert.AreEqual() that takes an IEqualityComparer<T> as parameter and another that takes a EqualityComparison<T>
Otherwise you could use Assert.AreEqual(Assert.XmlSerialize(a), Assert.XmlSerialize(b))
I would suggest that you override the Equals method on your class to perform the comparison you want. This allows you to define value equality instead of reference equality. One caveat is that you also have to override GetHashCode if you override Equals to ensure that two object that are equal also returns the same hash code. Here is a very simple example;
public class Foo {
public String Bar {
get;
set;
}
public String Baz {
get;
set;
}
public override Boolean Equals(Object other) {
Foo otherFoo = other as Foo;
return otherFoo != null
&& Bar.Equals(otherFoo.Bar)
&& Baz.Equals(otherFoo.Baz);
}
public override Int32 GetHashCode() {
return Bar.GetHashCode() ^ Baz.GetHasCode();
}
}
If you don't want to override Equals and you really just want to compare instances property by property you could use reflection:
public static Boolean AreEqual<T>(T a, T b) {
foreach (PropertyInfo propertyInfo in typeof(T).GetProperties())
if (!Object.Equals(propertyInfo.GetValue(a, null),
propertyInfo.GetValue(b, null)))
return false;
return true;
}
What I usually do is just implement the ToString() override - which is considered best a best practice to do anyways.
so in your case :
public override string ToString()
{
return string.Format("Class foo, bar={0}",bar);
}
then your AreEqual(foo1,foo2) will actually report the correct results as it will just call the default ToString implementation