Simplifying Value Comparison Semantics

A common chore in developing real-world C# applications is implementing value semantics for equality.  This involves implementing IEquatable<T>, overriding Equals() and GetHashCode(), and overloading the == and != operators.

Implementing these methods is a time-consuming and repetitive task, and is easy to get wrong, especially GetHashCode().  In particular, the best way implement GetHashCode() is much more complicated than return x.GetHashCode() ^ y.GetHashCode().

To simplify this task, I created a ValueComparer class:

///<summary>
/// Contains all of the properties of a class that 
/// are used to provide value semantics.
///</summary>
///<remarks>
/// You can create a static readonly ValueComparer for your class,
/// then call into it from Equals, GetHashCode, and CompareTo.
///</remarks>
class ValueComparer<T> : IComparer<T>, IEqualityComparer<T> {
    public ValueComparer(params Func<T, object>[] props) {
        Properties = new ReadOnlyCollection<Func<T, object>>(props);
    }

    public ReadOnlyCollection<Func<T, object>> Properties
            { get; private set; }

    public bool Equals(T x, T y) {
        if (ReferenceEquals(x, y)) return true;
        if (x == null || y == null) return false;
        //Object.Equals handles strings and nulls correctly
        return Properties.All(f => Equals(f(x), f(y)));    
    }

    //http://stackoverflow.com/questions/263400/263416#263416
    public int GetHashCode(T obj) {
        if (obj == null) return -42;
        unchecked {
            int hash = 17;
            foreach (var prop in Properties) {
                object value = prop(obj);
                if (value == null)
                    hash = hash * 23 - 1;
                else
                    hash = hash * 23 + value.GetHashCode();
            }
            return hash;
        }
    }

    public int Compare(T x, T y) {
        foreach (var prop in Properties) {
            //The properties can be any type including null.
            var comp = Comparer.DefaultInvariant
                .Compare(prop(x), prop(y));    
            if (comp != 0)
                return comp;
        }
        return 0;
    }
}

This class implements an external comparer that compares two instances by an ordered list of properties.

ValueComparer can be used as a standalone IComparer<T> or IEqualityComparer<T> implementation.

It can also be used to implement value semantics within a type.
For example:

class Person : IComparable<Person>, IEquatable<Person>, IComparable {
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Address { get; set; }
    public string Phone { get; set; }
    public string Email { get; set; }

    public override int GetHashCode() { return Comparer.GetHashCode(this); }
    public int CompareTo(Person obj) { return Comparer.Compare(this, obj); }
    int IComparable.CompareTo(object obj) { return CompareTo(obj as Person); }
    public bool Equals(Person obj) { return Comparer.Equals(this, obj); }
    public override bool Equals(object obj) { return Equals(obj as Person); }
    static readonly ValueComparer<Person> Comparer = new ValueComparer<Person>(
        o => o.LastName,
        o => o.FirstName,
        o => o.Address,
        o => o.Phone,
        o => o.Email
    );
}

To simplify this task, I created a code snippet:

<?xml version="1.0" encoding="utf-8" ?>
<CodeSnippets  xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
    <CodeSnippet Format="1.0.0">
        <Header>
            <Title>ValueComparer</Title>
            <Shortcut>vc</Shortcut>
            <Description>Code snippet for equality methods using ValueComparer</Description>
            <Author>SLaks</Author>
            <SnippetTypes>
                <SnippetType>Expansion</SnippetType>
            </SnippetTypes>
        </Header>
        <Snippet>
            <Declarations>
                <Literal Editable="false">
                    <ID>classname</ID>
                    <ToolTip>Class name</ToolTip>
                    <Default>ClassNamePlaceholder</Default>
                    <Function>ClassName()</Function>
                </Literal>
            </Declarations>
            <Code Language="csharp">
                <![CDATA[public override int GetHashCode() { return Comparer.GetHashCode(this); }
        public int CompareTo($classname$ obj) { return Comparer.Compare(this, obj); }
        int IComparable.CompareTo(object obj) { return CompareTo(obj as $classname$); }
        public bool Equals($classname$ obj) { return Comparer.Equals(this, obj); }
        public override bool Equals(object obj) { return Equals(obj as $classname$); }
        static readonly ValueComparer<$classname$> Comparer = new ValueComparer<$classname$>(
            o => o.$end$
        );]]>
            </Code>
        </Snippet>
    </CodeSnippet>
</CodeSnippets>
It can also be downloaded here; save it to My Documents\Visual Studio 2010\Code Snippets\Visual C#\My Code Snippets\

27 comments:

Pasting the ValueComparer class into VS 2010 C# gives me 6 errors.


The type or namespace name 'ReadOnlyCollection' could not be found (are you missing a using directive or an assembly

The type or namespace name 'ReadOnlyCollection' could not be found (are you missing a using directive or an assembly reference?)

Operator '==' cannot be applied to operands of type 'T' and 'T'

foreach statement cannot operate on variables of type 'ReadOnlyCollection>' because 'ReadOnlyCollection>' does not contain a public definition for 'GetEnumerator'

foreach statement cannot operate on variables of type 'ReadOnlyCollection>' because 'ReadOnlyCollection>' does not contain a public definition for 'GetEnumerator'

Using the generic type 'System.Collections.Generic.Comparer' requires 1 type arguments


Adding "using System.Collections.ObjectModel;" got rid of 4 of the errors, related to ReadOnlyCollection not being recognized, leaving me with these 2 errors:

Operator '==' cannot be applied to operands of type 'T' and 'T'

Using the generic type 'System.Collections.Generic.Comparer' requires 1 type arguments

Adding "using System.Collections;" fixes 1 of the remaining two errors. Leaving me with just:

Operator '==' cannot be applied to operands of type 'T' and 'T'

You're right; that's my fault.
I needed to call ReferenceEquals.

I fixed the code in the original post.

Thanks for catching my mistake!

Hi, Great.. Tutorial is just awesome..It is really helpful for a newbie like me.. I am a regular follower of your blog. Really very informative post you shared here. Kindly keep blogging. If anyone wants to become a .Net developer learn from Dot Net Training in Chennai. or learn thru Dot Net Training in Chennai. Nowadays Dot Net has tons of job opportunities on various vertical industry.
or Javascript Training in Chennai. Nowadays JavaScript has tons of job opportunities on various vertical industry.

I would like to thank you for the great text. Karina

In my opinion, it's very important to read https://samedaypaper.org/blog/narrative-essay-topics if you are looking for narrative essay writing advices. It was helpful for me and my friends when we were students.

Have questions to enter the online casino? Come to our section of rock BGAOC. best real online gambling slots Come and do not get lost. win with us.

Online biology essay services have come up with Biology Essay Writing Services for biology research paper writing service students in order for them to score straight A’s in their custom biology research paper services.

To seek the best Life Science Writing Services for those studying biology coursework writing services, it is important to hire an award winning science paper writing service company.

Amazing post, audience will be engaged at best with your blog, we are leading as AWS live class software development company willing to contribute to the educational sector with high end secured software for live classes.

Thanks for this important information through your website. QuickBooks Firewall Error acts as a barrier between the quickbooks company file and quickbooks desktop. It doesn't allow the quickbooks software to communicate with the quickbooks company file and this error has been experienced by the users many times.quickbooks database server manager windows firewall is blocking quickbooks

I look forward to fresh updates and will share this website with my Facebook group!
McAfee programming gives the digital security services to ensure your hardware information.Install mcafee from www.mcafee.com/activate |
How to use McAfee Removal tool ?
What is McAfee total protection Error while installing updates on Mac ?
What is McAfee LiveSafe Connect VPN and its benefits?
How to Uninstall Avast in Windows 10

How McAfee Total Protection helps you to be secure on the internet?
What is McAfee LiveSafe Security.
How to Register McAfee on Lenovo ?
How to Register McAfee on dell ?

It's really a nice and useful piece of info.
Setup your ms office from office.com/setup |
What is the use of Windows 10 media creation tool
how to find How to find windows 10 product key
Do you know you can Install office without account .
How to Create Windows 10 recovery USB

I look forward to fresh updates and will share this website with my Facebook group!
Find your HP printer support
Easy way for How to connect hp printer to wifi
Why is my HP printer offline
Fix your printer by printer troubleshooting
Why is my printer connected but not printing

Money market There is no need to be physically present for trading securities, as one can trade from anywhere through the internet or telephone

Merkur 15c Safety Razor - Barber Pole - Deccasino
Merkur casinosites.one 15C Safety Razor - casino-roll.com Merkur - https://deccasino.com/review/merit-casino/ 15C for https://jancasino.com/review/merit-casino/ Barber Pole is the 바카라 사이트 perfect introduction to the Merkur Safety Razor.

Canon IJ Network Tool you to watch out for the points mentioned below considerably:
If you want a LAN setup for your printer, you should have the required connectivity equipment such as Network Access Point (Router/ Modem), LAN Cable etc.To get your IJ Network tool to work, you first need to check your printer’s connectivity via LAN connection. Next, check your LAN cable carefully.Canon IJ Printer Utility you can alter your printer’s ink cartridge settings according to your requirements. If any ink cartridges get empty, you can continue to print with other available cartridges after changing the settings.

Visit ij.start canon | ij.start.cannon and find out the best way to download Canon printer drivers. Canon printers are ideal for every situation wherever you need a document, paper, or photo print or even if you wish to scan, fax, and do more.

All-in-one Canon Inkjet printers are suitable for home, business, school, and others to improve productivity. You can easily set up your Canon printer through drivers from Canon.com/ijsetup | canon.come/ijsetup , wireless connection, USB, and a few components.

ij.start.canon
is the manufacturer site to download Canon printer drivers. Install and set up Canon Printer from https: //ij.start.canon and obtain high-quality printing documents straightforwardly.

https//ij.start.cannon is actually the official site of ij start canon that helps you install the latest printer drivers and software. Visiting http //ij.start.cannon
provides you a complete list of all canon printers where you’ve to select your printer model and download the correct setup file

Canon IJ Network Tool is a toolkit software with the options to keep a check on most of your Canon printer network settings and adjust them according to your requirements.

Canon IJ Printer Utility is a complete software package meant to adjust and modify the configurations of your printer device as per the requirement. It is one of the essential utility software offered by Canon to ease your printer configuration alteration using a few clicks.


Canon.com/ijsetup/mg2500
is the Canon support link to get you the latest printer drivers and software to set up your PIXMA MG2500 or MG2520.

ij.start canon helps to set up canon printer. It’s the online support platform to download and install canon printer drivers, firmware, and software ij.start.canon , Canon IJ Network Tool

To keep current, you need to find trustworthy technology news sources that will provide you with up-to-date information.

blackboard san jac

inverse function calculator

qhs medical abbreviation

Post a Comment