Overriding GetHashCode() for value objects without fields - c#

Sometimes I need value objects without fields (message headers, schemas, etc.), for example:
abstract class RequestHeader
{
}
sealed class FirstRequestHeader : RequestHeader
{
}
I use them in methods like:
partial class Server
{
private readonly IReadOnlyDictionary<RequestHeader, Action<object>> requestMap;
public void ProcessRequest(RequestHeader header, object request)
{
requestMap[header](request);
}
}
In this case default implementation of GetHashCode and Equals methods totally fits my needs, because I can use singletons.
But since FirstRequestHeader is an immutable value object I want it to behave like a real value object:
var a = new FirstRequestHeader();
var b = new FirstRequestHeader();
Console.WriteLine(a == b &&
a.Equals(b) &&
a.GetHashCode() == b.GetHashCode()); // False, but should be True
Overriding == operator and Equals method is easy.
But what is correct or recommended way of overriding GetHashCode method in this case?
I can expect some answers (all with some drawbacks):
hardcode constant hashcode for each type
generate one each execution and save it in a static field
use type's hashcode through GetType method
avoid empty objects (add a field)
But no assumption was confirmed by searching
So, what would you do?

If there is no data associated with the class then make only one instance.
sealed class FirstRequestHeader : RequestHeader
{
public static readonly FirstRequestHeader Value = new FirstRequestHeader();
private FirstRequestHeader()
{
}
}

hardcode constant hashcode for each type
If you want two "identical" objects to be treated as equal (and with no fields or your instances are identical), this is definitely the way to go.
Adding a new field, which I assume you won't modify in any meaningful way results in the same, just overcomplicates this. Same can be said for the other two approaches.
Please note that you can choose any value - you do not need to worry about possible hash code collisions between different types, so keep it simple.

If you want all instances to have the same hashcode without using constants you could also use the hashcode of the type:
public class FirstRequestHeader
{
public override int GetHashCode()
{
return this.GetType().GetHashCode();
}
}

Related

Can C# generics support Class or Nullable?

In my current project, i have a Value<T> class.
Currently T can be anything, but we must support Null values, so currently we use it in two forms:
Value<string> or Value<int?>
Can I in any way create a Value class that would allow me to specify Value<string> or Value<int>, but where the effect is that Value holds T for classes, but holds T? for structs?
The goal is to avoid the case where a developer specifies Value<int> and we later have problems, because we dont handle Null values properly.
Ie, id like Compiler suport for avoiding errors.
Can I in any way create a Value class that would allow me to specify Value<string> or Value<int>, but where the effect is that Value holds T for classes, but holds T? for structs?
No, because you cannot have "or" logic in generic type constraints.
To achieve "or" logic in generic type constraints, you would have to create two separate generic classes, each with their own generic type constraint. Note that these two classes could inherit from a shared generic base class which has no type constraint at all.
If that base type is abstract, then you can be sure that consumers must have passed one of the derived classes' type constraint check (assuming no one added some other derived classes)
It would be more appropriate to change your expectation instead of trying to make it the way you currently want to.
but we must support null values
If instead of null, you use default(T), then the problem is resolved.
For class types, default(MyClass) effectively resolves to null
For structs, default(MyStruct) returns a struct whose properties all contain their default values
default(MyStruct) is the common way to use the concept of "nullability" without having to use a literal null value.
A usage example:
public class Container<T>
{
private readonly Random _random = new Random();
public T DoSomething(T input)
{
//always returns "nothing"
return default(T);
}
}
public class MyClass
{
public int Value { get; set; }
}
public struct MyStruct
{
public int Value { get; set; }
}
public class Test
{
public bool ContainerReturnsNothing<T>(T input)
{
var container = new Container<T>();
var output = container.DoSomething(input);
return output.Equals(default(T));
}
public void TestAClassAndAStruct()
{
ContainerReturnsNothing(new MyClass() {Value = 1}); // true
ContainerReturnsNothing(new MyStruct() {Value = 1}); // true
}
}
In the TestAClassAndAStruct method you can see that this generic call stack works exactly the same regardless of whether you use a class or a struct.
If you change the container to return input; then ContainerReturnsNothing will return false in both cases.
One thing you may need to be aware of is that a "nothing" struct cannot be differentiated from a struct that was created but whose properties all happen to have default values. If a struct whose properties all happen to have default values, is a meaningful (i.e. not-nothing) struct value in your case, then this is an issue.
A simple example here is int, whose default(int) resolves to 0. If 0 is a meaningful value, then it is therefore not nothing, which means that you cannot use 0 to represent nothingness.
But you can work around that issue by adding a property which is forced to contain a non-default value when a constructor is executed:
public struct MyStruct
{
public bool IsConstructed { get; } // default false
public int Value { get; }
public MyStruct(int myValue)
{
this.IsConstructed = true;
this.Value = myValue;
}
}
default(MyStruct) will always have IsConstructed set to false.
Every instantiated struct will always have IsConstructed set to true.
This avoid the issue since they will never be equal to one another. In other words:
var myStruct = new MyStruct(0);
var isNull = myStruct.Equals(default(MyStruct));
isNull is false because myStruct and default(MyStruct) contain a different value for IsConstructed (true and false, respectively).
If you run this same check using the MyStruct class from the original example, isNull would be true because all the properties match, i.e. myStruct and default(MyStruct) both have a Value property set to 0.

If I implement IEquatable<T>, will I lose the option to compare by reference?

I would like to compare an object with antoher to know if they are equal or not. So it seems the way to do that is implementing the IEquatable interface in my class.
But I am not sure about how this affect to the behaviour of my class. Now, in my code, I use to compare two object by reference in this way:
if(myObject1 == myObject2)
{
// code when both objects are the same.
// Set values in some properties and do some actions according that.
}
else
{
// code when both objects are no the same.
// Set values in some properties and do some actions according that.
}
But in some special cases, mainly in testing, I would like to compare 2 objects and considerate equal if all the properties are equal, but in this case I don't know if it will affect to my main code, in which I am compare by reference.
Another option could be implement a method that compare in this way, but I don't know if it is a good idea or it is better to implement the IEquatable interface.
Thanks.
There are several different things going on here.
The first is that IEquatable<T> is not directly related to the == operator. If you implement IEquatable<T>, but you don't override the == operator, then == will continue to do what it currently does: compare your objects by reference.
IEquatable<T> gives you an Equals(T) method, and that's it. By itself, it doesn't affect Equals(object) (which you also need to implement), or == and !=.
So let's assume that you do overload the == operator, to call our Equals method:
public static bool operator ==(Foo left, Foo right) => Equals(left, right);
public static bool operator !=(Foo left, Foo right) => !Equals(left, right);
This has only changed the == operator between two Foo instances. You can still write:
if ((object)myObject1 == (object)myObject2))
and that will fall back to using object's == method, which compares by reference.
Another way to do this is:
if (ReferenceEquals(myObject1, myObject2))
which just does the same thing.
Also note that it's rare to implement IEquatable<T> for classes: there's really no point. Classes already have an Equals(object) method and a GetHashCode() method which you need to override, and adding an Equals(T) method doesn't give you much.
IEquatable<T> is however useful for structs: they also have an Equals(object) method you need to override, but if you actually call it then you're going to end up boxing, since it accepts object. If you implement IEquatable<T> here then you also get an Equals(T) method, which you can call without boxing anything.
All of that said, I would write your code as it's intended to work in your application, and do any testing-specific stuff in your test project. This means that if your objects should be compared by reference in your code, I wouldn't add anything new to the object itself.
In your test project, you can write your own method to check whether two instances of your object have the same properties (either as a custom bool AreFoosEqual(Foo f1, Foo f2), or as a full-blown IEqualityComparer<Foo> instance). You can then make this do exactly what your tests need, without worrying about breaking your application.
You can also write your test method as a series of assertions, which tells you which property is incorrect, and what the difference is. This can give you richer test output:
public static void AssertFoosEquals(Foo f1, Foo f2)
{
Assert.AreEqual(f1.Foo, f2.Foo, "Foo property mismatch");
Assert.AreEqual(f1.Bar, f2.Bar, "Bar property mismtach");
}
If you want to compare same objects but in different ways, I suggest using a comparer which implements IEqualityComparer<T>:
public class MyClassTestComparer : IEqualityComparer<MyClass> {
public bool Equals(MyClass x, MyClass y) {
if (ReferenceEquals(x, y))
return true;
else if (null == x || null == y)
return false;
return x.Propery1 == y.Property1 &&
x.Propery2 == y.Property2 &&
x.ProperyN == y.PropertyN;
}
public int GetHashCode(MyClass obj) {
return obj == null
? 0
: obj.Propery1.GetHashCode() ^ obj.Propery2.GetHashCode();
}
}
then you can choose the right comparer
public static IEqualityComparer<MyClass> MyClassComparer {
if (we_should_use_test_comparer)
return new MyClassTestComparer();
else
return EqualityComparer<MyClass>.Default;
}
Finally if will be
if (MyClassComparer.Equals(myObject1, myObject2)) {
// Equals: by reference or by properties (in test)
}
When you make a unit test ->
Like:
public void TestSomething()
{
var expectedValue1 = "SomeExpectedValue";
var actualValue = instance.Method();
Assert.Equal(expectedValue1, actualValue);
}
Then you "simply" assert the properties you want to look at, if you return an object and not a value:
public void TestSomething()
{
var expectedValue1 = "SomeExpectedValue";
TestableObject subject = instance.Method();
Assert.Equal(expectedValue1, subject.Somevalue);
}
If you want a more generic setup, you can write a reflection using generic flow, that looks at all properties on an object and attempts to match them to the another provided object.
Or you could download a nuget package of tools that already allow you to do this.
I would not override any functionality, simply for the purpose of testing. That way lies spaghetti code.
Ideally your code should be 100% verifiable by unit tests, without having specific code sections that augment or assist your testing methods. (Unless said code is restricted to the test project itself, and is not contained within any of the actual code being tested.

Are custom objects equal by value with List<>

I have the following classes:
public class MyDocuments
{
public DateTime registeredDate;
public string version;
public List<Document> registeredDocuments;
}
public class Document
{
public string name;
public List<File> registeredFiles;
}
public class File
{
public string name;
public string content;
}
I have an instance of MyDocuments which has several documents in List<Document> registeredDocument. I get a new List<Document> from the user.
How can I verify that the new object doesn't exist in the list? I want to compare by value not reference.
I'm thinking of using HashSet instead of List. Is this the proper approach?
How are equality comparisons performed?
Whenever the BCL classes want to perform an equality check between objects of some type T, they do so by calling one or both of the methods in some implementation of IEqualityComparer<T>. To get hold of such an implementation, the framework looks to EqualityComparer<T>.Default.
As mentioned in the documentation, this property produces an IEqualityComparer<T> like this:
The Default property checks whether type T implements the
System.IEquatable<T> interface and, if so, returns an
EqualityComparer<T> that uses that implementation. Otherwise, it
returns an EqualityComparer<T> that uses the overrides of
Object.Equals and Object.GetHashCode provided by T.
What are my options?
So, in general, to dictate how equality comparisons should be performed you can:
Explicitly provide an implementation of IEqualityComparer<T> to the class or method that performs equality checks. This option is not very visible with List<T>, but many LINQ methods (such as Contains) do support it.
Make your class implement IEquatable<T>. This will make EqualityComparer<T>.Default use this implementation, and is a good choice whenever there is an obvious "natural" way to compare objects of type T.
Override object.GetHashCode and object.Equals without implementing IEqualityComparer<T>. However, this is simply an inferior version of #2 and AFAIK should always be avoided.
Which option to pick?
A good rule of thumb is: if there is an obvious and natural way to compare objects of class T, consider having it implement IEquatable<T>; this will make sure your comparison logic is used throughout the framework without any additional involvement. If there is no obvious candidate, or if you want to compare in a manner different than the default, implement your own IEqualityComparer<T> and pass the implementation as an argument to the class or method that needs to perform equality checks.
You will need to implement the Equals() method, and probably GetHashCode() as well. See this answer for an example.
You should implement IEquatable<T>.
When you implement this interface on your custom object, any equality checks (e.g. Contains, IndexOf) are automatically done using your objects implementation.
override the object.Equals method.
here's an example straight from the documentation
public class Person
{
private string idNumber;
private string personName;
public Person(string name, string id)
{
this.personName = name;
this.idNumber = id;
}
public override bool Equals(Object obj)
{
Person personObj = obj as Person;
if (personObj == null)
return false;
else
return idNumber.Equals(personObj.idNumber);
}
public override int GetHashCode()
{
return this.idNumber.GetHashCode();
}
}
the Equals method returns a bool which is whether or not obj is equal to this
Something like this at the top level, continued down at the sub-levels:
public class MyDocuments
{
public DateTime registeredDate;
public string version;
public HashSet<Document> registeredDocuments;
public override bool Equals(Object o)
{
if( !(o is MyDocuments) ) return false;
MyDocuments that = (MyDocuments)o;
if( !String.Equals(this.version, that.version) ) return false;
if( this.registeredDocuments.Count != that.registeredDocuments.Count ) return false;
// assuming registeredDate doesn't matter for equality...
foreach( Document d in this.registeredDocuments )
if( !that.registeredDocuments.Contains(d) )
return false;
return true;
}
public override int GetHashCode()
{
int ret = version.GetHashCode();
foreach (Document d in this.registeredDocuments)
ret ^= d.GetHashCode(); // xor isn't great, but better than nothing.
return ret;
}
}
Note: Caching could be useful for the HashCode values if the properties were change-aware.

What is the difference between using class and struct with Dictionary.ContainsKey()?

Below is a sample of my dictionary definition. When I define DicKeys as a class, ContainsKey() doesn't work. If I change DicKeys to a struct, it works properly.
Why does ContainsKey() work differently for a class than it does for a struct?
Dictionary<DicKeys, DicVals> aDic = new Dictionary<DicKeys, DicVals>();
// original version as below
public Class DicKeys
{
public EnKey1 DicKeyItem1,
public EnKey2 DicKeyItem2,
}
// revised version as below
public struct DicKeys
{
public EnKey1 DicKeyItem1,
public EnKey2 DicKeyItem2,
}
// common parts of code below
public enum EnKey1
{
A1,
A2,
}
public enum EnKey2
{
B11,
B12,
}
DicKeys aDicKey = new DicKeys();
// assigned value to aDicKey obj here;
if (aDic.ContainsKey(aDicKey ) == true)
{
// do some thing here
// If I defined as 'class', it doesn't hit here.
// Updated to 'struct', it hit here.
}
Well, you haven't shown where you're populating the dictionary or what sfTKey is... but I strongly suspect it's because you haven't overridden Equals or GetHashCode in DicKeys.
By default, classes use reference identity for equality - in other words, two key references will only compare as equal if they refer to the exact same object. You can override Equals and GetHashCode to provide equality based on the contents of the objects though. Value types (structs) automatically use value-based equality, but I certainly wouldn't recommend using a mutable struct as you've got here. (I wouldn't recommend using public fields at all, to be honest.)
See this question for an example of the kind of thing you might do in Equals and GetHashCode - and some other members you may want to provide on types which have value-based equality.

Anonymous inner classes in C#?

Is there something like anonymous inner classes (used in Java) in C#?
I explain what I would use it for by example: I'm declaring and initializing field of type IDictionary<Person, Account> and I need to write custom IEqualityComparer<Person>. That is because I want two Persons to be treated as equal by the IDictionary when they have equal names and IDs (not only IDs as it is by default). I will not need this IEqualityComparer<Person> anywhere else in the code.
So I do I have to declare new class that implements IEqualityComparer<Person> to do this ? In Java I would use anonymous class, something like this(this is mixed C#-Java syntax, just to show what functionality I'm looking for):
IDictionry<Person, Account> myDict = new Dictionary<Person, Account>(
new IEqualityComparer<Person>(){
public bool Equals(Person a, Person b){
return a.Id == b.Id && a.Name == b.Name;
}
public int GetHashCode(Person p){
return p.Id.GetHashCode() * p.Name.GetHashCode();
}
});
Is something like this in C# ? I'm too lazy to write new class every time I need something like this.
Note: This is syntax question. I know how to write it, but I want to know if it's possible to make the code shorter.
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
EDIT: How do you yourself code similar cases ? Do you create new class to implement the interface or what do you do ? Maybe you have some trick that I might like.
EDIT What about future support for anonymous classes like those in Java ? Have you heard something about it ?
EDIT: Well I see I'll have to provide my actual code - not just an example. That's because I don't know if it's going to work with Jon's Skeet's solution.
The actual reason why I don't just implement Equals(object) and GetHashCode in the class itself is, that it's class(entity) generated by E-R framework from model diagram. If I implemented it in class itself my code would be deleted from the class(entity) every time I update the model from database (using "update from database" feature). The class is actually called Font not Person. It has this properities:
Id: int
FamilyName:string
Size:int
Bold:bool
Italic:bool
Underlined:bool
Striked:bool
Foreground:Color
Where Color is another class (entity) generated from database.
This are properties of Color:
Id:int
Alpha:byte
Red:byte
Green:byte
Blue:byte
So I cannot modify Font, neither Color (if I don't want to rewrite those changes over and over again every time I change database) What I want is to have this Dictionary:
private IDictionary<Font, Something> cache = new Dictionary<Font, Something>(new SomeEqualityComparer());
And the comparer SomeEqualityComparer should ensure that two Fonts would be considered equal if and only if all the properties listed above(except Id) are equal. In the case of last property Foreground two Colors are considered equal when all their properties(except Id) are equal.
Now if I use solution that Jon Skeet has kindly recommended me, I'm not sure if that can be ensured.
If I used something like:
private IDictionary<Font, Something> cache = new Dictionary<Font, Something>(ProjectionEqualityComparer<Font>.Create
(f => new { f.FontName, f.Size, f.Bold, f.Italic, f.Underlined, f.Striked, f.Foreground});
I'd guess that anonymous types call Equals(object) on all properties when their Equals(object) is called. However as I cannot override Color's Equals(object) it would not compare Colors as I want (using all properties except Id) so also the equality of Fonts would be tested incorrectly. Am I right ?
I have a ProjectionEqualityComparer class you could use in MiscUtil. You'd use code like this:
IEqualityComparer<Person> comparer = ProjectionEqualityComparer<Person>.Create
(p => new { p.Name, p.Id });
Thhat uses the fact that anonymous types have appropriate equality notions built in - when the ProjectionEqualityComparer is asked to compare two people for equality, it will project each to the anonymous type, and compare those instances. Likewise when it's asked for a hashcode, it will perform the projection and ask that for its hash code.
EDIT: To tackle your colour problem, you're right: if Color doesn't override Equals/GetHashCode in the way that you want, you can't use it directly. However, you can do this instead:
private IDictionary<Font, Something> cache = new Dictionary<Font, Something>
(ProjectionEqualityComparer<Font>.Create(f => new {
f.FontName, f.Size, f.Bold, f.Italic, f.Underlined, f.Striked,
f.Foreground.Alpha, f.Foreground.Red, f.Foreground.Green,
f.Foreground.Blue});
If you're able to modify the Color type in terms of properties, it would be simpler if you could give it an ARGB property generated from the others, so you could write:
private IDictionary<Font, Something> cache = new Dictionary<Font, Something>
(ProjectionEqualityComparer<Font>.Create(f => new {
f.FontName, f.Size, f.Bold, f.Italic, f.Underlined, f.Striked,
f.Foreground.ARGB });
That's pretty ugly, but it should work...
In your last edit you mention that the reason that you don't implement Equals and GetHashCode is because the code for your classes is auto-generated and you don't want to have to re-implement that code each time you regenerate the code.
That's one of the scenarios for which partial classes were introduced in C#
A lot of code generation tools will generate classes with the partial keyword to allow you to take advantage of that feature. Check if the classes that are being generated for your code are partial.
In a separate file (or files) that won't be overwritten when you regenerate the code, within the same assembly, you could have something like the following:
partial class Font
{
public override bool Equals(object obj)
{
// ...
}
public override int GetHashCode()
{
// ...
}
}
partial class Color
{
public override bool Equals(object obj)
{
// ...
}
public override int GetHashCode()
{
// ...
}
}
No there isn't. There are anonymous types e.g.
var MyType = new { id=1, name="john", dept = "sales" };
but they are very limited, and only contain read only properties and no methods.
The literal answer is that no, C# doesn't have anonymous inner classes, because Java added those to get around its lack of first-class functions, which C# does have. More specifically, to solve your problem, you can just implement IEquatable<Person> on your Person class, and then IDictionary will use that automatically. That's the most common solution to this problem and works as long as your OK with the process for comparing Persons being baked into that class.
If you want the comparison/equality logic to not be tied directly to Person, most collections in .NET allow you to pass in a Comparison<T> object (which is a delegate, not an interface), letting you do nice in-place sorting logic. For example, to sort a list of people by name, you could do:
List<Person> people = ...
people.Sort((x, y) => x.Name.CompareTo(x.y));
Unfortunately, Dictionary doesn't have something similar to an equality function. In .NET 4.0, the stock answer seems to be to override EqualityComparer<T>:
public class PersonComparer : EqualityComparer<Person>
{
public override bool Equals(Person a, Person b)
{
return a.Id == b.Id && a.Name == b.Name;
}
}
Having to define a new class each time you need to compare, though, is a chore. What I'd do is make a generic one that takes a function:
public class Equality<T> : EqualityComparer<T>
{
public Equality(Func<T, T, bool> comparer)
{
this.comparer = comparer;
}
public override bool Equals(T a, T b)
{
return comparer(a, b);
}
private Func<T, T, bool> comparer;
}
Add a little helper class:
public static class Equality
{
public static Equality<T> Create<T>(Func<T, T, bool> comparer)
{
return new Equality<T>(comparer);
}
}
And then your solution becomes:
IDictionary<Person, Account> myDict = new Dictionary<Person, Account>(
Equality.Create((a, b) => a.Id == b.Id && a.Name == b.Name);
Even shorter than it would be in Java.
The closest you're going to get is anonymous types like you'd see in a LINQ expression. A short example from the link:
var v = new { Amount = 108, Message = "Hello" };
Definitely not what you're looking for. I haven't heard of future support for anonymous classes in C# either.
You could define the implementation of the interface in one place, 1 class, map the interface to your desired implementation class in your favorite IOC framework and not have to think about instantiating a 1-time-use anonymous implementation at all.
No, as of the time this question was originally written (C# 3.0), there is not.

Categories

Resources