Equality in.net. Gregory Adam 07/12/2008. This article describes how equality works in.net

Similar documents
The class Object. Lecture CS1122 Summer 2008

For this section, we will implement a class with only non-static features, that represents a rectangle

Creating an Immutable Class. Based on slides by Prof. Burton Ma

Chapter 10. Learning Objectives

equals() in the class Object

Learn C# Errata. 3-9 The Nullable Types The Assignment Operators

Methods Common to all Classes

IST311. Advanced Issues in OOP: Inheritance and Polymorphism

Super-Classes and sub-classes

COMP 250. Lecture 30. inheritance. overriding vs overloading. Nov. 17, 2017

Chapter 11: Collections and Maps

The Object Class. java.lang.object. Important Methods In Object. Mark Allen Weiss Copyright 2000

Overloaded Methods. Sending Messages. Overloaded Constructors. Sending Parameters

Expected properties of equality

CSE 331 Software Design & Implementation

The Liskov Substitution Principle

Principles of Software Construction: Objects, Design and Concurrency. Polymorphism, part 2. toad Fall 2012

Object-Oriented Programming in the Java language

java.lang.object: Equality

CSE 331 Software Design & Implementation

Collections. Powered by Pentalog. by Vlad Costel Ungureanu for Learn Stuff

Inheritance (Part 5) Odds and ends

Programming Languages and Techniques (CIS120)

Not overriding equals

Semantic & Immutable Types

Domain-Driven Design Activity

Java Comparable interface

Equality. Michael Ernst. CSE 331 University of Washington

Introduction to C# Applications

.Net Technologies. Components of.net Framework

Uguaglianza e Identità. (no, non avete sbagliato corso )

COMP 250 Fall inheritance Nov. 17, 2017

Elementary Symbol Tables

Object Oriented Programming in C#

COMP 250. Lecture 32. interfaces. (Comparable, Iterable & Iterator) Nov. 22/23, 2017

Java Fundamentals (II)

Java and C# in Depth

CMSC131. Inheritance. Object. When we talked about Object, I mentioned that all Java classes are "built" on top of that.

Memorandum public override string string Node while null return public void bool false Node while null null true while public void Node new

inside: THE MAGAZINE OF USENIX & SAGE August 2003 volume 28 number 4 PROGRAMMING McCluskey: Working with C# Classes

Canonical Form. No argument constructor Object Equality String representation Cloning Serialization Hashing. Software Engineering

Announcements. Equality. Lecture 10 Equality and Hashcode. Announcements. CSE 331 Software Design and Implementation. Leah Perlmutter / Summer 2018

Equality. Michael Ernst. CSE 331 University of Washington

Lesson11-Inheritance-Abstract-Classes. The GeometricObject case

Programming Languages and Techniques (CIS120)

Advanced Topics on Classes and Objects

Software Engineering Design & Construction

MET08-J. Preserve the equality contract when overriding the equals() method

Programming Languages and Techniques (CIS120e)

Programming Languages and Techniques (CIS120)

Java Persistence API (JPA) Entities

Today. Book-keeping. Inheritance. Subscribe to sipb-iap-java-students. Slides and code at Interfaces.

Inheritance. Notes Chapter 6 and AJ Chapters 7 and 8

Advanced Programming - JAVA Lecture 4 OOP Concepts in JAVA PART II

INHERITANCE. Spring 2019

Advanced Java Concepts Unit 3: Stacks and Queues

Chapter 1 Getting Started

Modern C++ for Computer Vision and Image Processing. Igor Bogoslavskyi

Introduce C# as Object Oriented programming language. Explain, tokens,

CMSC132 Summer 2018 Midterm 1


Programming Languages and Techniques (CIS120)

Principles of Software Construction: Objects, Design and Concurrency. Inheritance, type-checking, and method dispatch. toad

Introduction to Programming Using Java (98-388)

Effective C# Presentation By: Brian Braatz. Derived from the book Effective C# 2 nd Edition

CannonAttack v1.0. A Test Driven Development Tutorial in C# 4.0 Author: Dominic Millar Tech Review:Matt Rumble Editor:Cathy Tippett

Tokens, Expressions and Control Structures

ELEMENTARY SEARCH ALGORITHMS

C # 7, 8, and beyond: language features from design to release to IDE support. Kevin

COPYRIGHTED MATERIAL. Contents. Part I: C# Fundamentals 1. Chapter 1: The.NET Framework 3. Chapter 2: Getting Started with Visual Studio

C++_ MARKS 40 MIN

Hierarchical inheritance: Contains one base class and multiple derived classes of the same base class.

Polymorphism. return a.doublevalue() + b.doublevalue();

Objectives. Introduce the core C# language features class Main types variables basic input and output operators arrays control constructs comments

Inheritance and Polymorphism

COMP200 - Object Oriented Programming: Test One Duration - 60 minutes

PES INSTITUTE OF TECHNOLOGY

What is an interface? Why is an interface useful?

What property of a C# array indicates its allocated size? What keyword in the base class allows a method to be polymorphic?

Midterm Exam. Sample Solutions

Java Magistère BFA

INSTRUCTIONS TO CANDIDATES

Programming Languages and Techniques (CIS120)

CMSC132 Summer 2018 Midterm 1. Solution

CS61B Spring 2016 Guerrilla Section 2 Worksheet

COS226 - Spring 2018 Class Meeting # 13 March 26, 2018 Inheritance & Polymorphism

Class, Variable, Constructor, Object, Method Questions

CLASS DESIGN. Objectives MODULE 4

Repeating Instructions. C# Programming: From Problem Analysis to Program Design 2nd Edition. David McDonald, Ph.D. Director of Emerging Technologies

EEE-425 Programming Languages (2013) 1

1.00/1.001 Introduction to Computers and Engineering Problem Solving. Final Exam

Framework Fundamentals

CS 455 Midterm Exam 2 Fall 2016 [Bono] November 8, 2016

CS 211: Inheritance. Chris Kauffman. Week 5-2

C++ C and C++ C++ fundamental types. C++ enumeration. To quote Bjarne Stroustrup: 5. Overloading Namespaces Classes

C# s A Doddle. Steve Love. ACCU April 2013

COE318 Lecture Notes Week 8 (Oct 24, 2011)

CS 162, Lecture 25: Exam II Review. 30 May 2018

CMSC 132: Object-Oriented Programming II

Abstract and final classes [Horstmann, pp ] An abstract class is kind of a cross between a class and an interface.

Transcription:

Equality in.net Gregory Adam 07/12/2008 This article describes how equality works in.net

Introduction How is equality implemented in.net? This is a summary of how it works. Object.Equals() Object.Equals() tells you in the most general way if two objects are equal. There are two meanings of equivalence: one for value types and one for reference types. (1) Value types The default implementation for value type classes iterates over the internal fields comparing them for value equality. Let s define a struct and test the speed. The following executes in 7.56 sec You may wonder what the ExecuteTimed()is. It measures the execution time of a method. The source is included in Appendix A. public struct RectangleStruct double Width; class test_struct const int times = 100000000; static void Main(string[] args) ((delegatevoid)testequalstruct).executetimed(true); static void TestEqualStruct() RectangleStruct x = new RectangleStruct(); RectangleStruct y = new RectangleStruct(); bool b; for (int i = times; --i!= 0; ) b = x.equals(y); ; You may wonder whether the speed can be improved. As it happens, yes we can by implementing an override implementation of Equals()

Before we do that, there are some rules to adhere to. Let s examine them - x.equals(x) must be true - x.equals(y) must yield the same result as y.equals(x) - if x.equals(y) and y.equals(z) is true, then x.equals(z) must be true - x.equals(null) is false for all x that are not null - Equals() must not throw any exceptions Let s try. Overriding the Equals() results in 4.98 secs which is a third faster. public struct RectangleStruct double Width; // IEquatable public override bool Equals(object obj) RectangleStruct other; if (obj!= null && obj is RectangleStruct) other = (RectangleStruct)obj; return (Width == other.width) && (Height == other.height); // the class Test is the same You may have noticed that the value type has to be boxed to an object, i.e. the argument of Equals is boxed to cast it to an object prior to each call to Equals(). Can we do any faster? Yes... The object.equals() implements the IEquatable interface. In addition to that, we can implement the IEquatable<T> interface. This sounds like a mouthful, but in essence, it s just adding an overloaded method of Equals() which accepts another RectangleStruct. If we do, the compiler will call that overloaded method which, as you may have guessed, does not need boxing. The following code executes in 2.44 seconds. Equals(RectangleStruct other) is called instead of Equals(object obj) So, if the argument is a RectangleStruct, the execution time is reduced to slightly over 30% of the original. IEquatable< RectangleStruct> on the first line indicates that the struct implements the IEquatable<T> interface.

public struct RectangleStruct : IEquatable<RectangleStruct> double Width; // IEquatable public override bool Equals(object obj) RectangleStruct other; if (obj!= null && obj is RectangleStruct) other = (RectangleStruct)obj; return (Width == other.width) && (Height == other.height); // IEquatable<T> public bool Equals(RectangleStruct other) return (Width == other.width) && (Height == other.height); public override int GetHashCode() return Width.GetHashCode() ^ Height.GetHashCode(); // the class Test is the same One final note If you override Equals() then it is best to override GetHasCode() too. GetHasCode () is called when objects are stored in a hash table (Dictionary, HashSet,...). The value returned by GetHashCode() will be used as the key. The rules for GetHashCode() are as follows: - If x.equals(y), then x.gethashcode() and y.gethashcode() must return the same result - HashCodes do not need to be unique. - Never throw an exception from within GetHashCode() So, for completeness sake, I have added GetHashCode() in the code above. (2) Reference types Let s examine the reference types. The default behaviour is identity equivalence. It just means that their references must be equal, i.e. var1 and var2 must point to the same object. Sometimes, it feels more natural to return a value type result. Suppose we had implemented the Rectangle as a reference type. Would it not make more sense for the Equals() method to return whether their values are all equal? If you do override Equals() you can still test whether two variables point to the same object by using the static method ReferenceEquals() of the object class.

Since the default of object.equals() is a reference comparison and we want value type behaviour, let s move to our own implementation which executes in 2.96 sec. public class RectangleReference double Width; // constructors public RectangleReference() Width = Height = 0.0; public RectangleReference(double width, double height) Width = width; Height = height; // IEquatable public override bool Equals(object obj) // this cannot be null if( obj == null ) // same class? RectangleReference other; if( (Object) (other = obj as RectangleReference)!= null ) return (Width == other.width) && (Height == other.height); // obj is another type class test_class const int times = 100000000; static void Main(string[] args) ((delegatevoid)testequalreference).executetimed(true); static void TestEqualReference() RectangleReference x = new RectangleReference(); RectangleReference y = new RectangleReference(); bool b; for (int i = times; --i!= 0; )

; b = x.equals(y); Now, like in the value type, let s add the IEquatable<T> The code below executes in 2.65 sec (compared to 3.10 sec) which is only a bit faster public class RectangleReference : IEquatable<RectangleReference> double Width; // constructors public RectangleReference() Width = Height = 0.0; public RectangleReference(double width, double height) Width = width; Height = height; // IEquatable public override bool Equals(object obj) // this cannot be null if( obj == null ) // same class? RectangleReference other; if( (Object) (other = obj as RectangleReference)!= null ) return (Width == other.width) && (Height == other.height); // obj is another type // IEquatable<T> public bool Equals(RectangleReference other) // this cannot be null if ((Object)other == null) return (Width == other.width) && (Height == other.height); public override int GetHashCode() return Width.GetHashCode() ^ Height.GetHashCode(); // the class Test is the same

Implementing the == and!= operators Adding the == and!= operators is just a small step. We can use object.equals() (1) Value type public struct RectangleStruct : IEquatable<RectangleStruct> double Width; // IEquatable public override bool Equals(object obj) RectangleStruct other; if (obj!= null && obj is RectangleStruct) other = (RectangleStruct)obj; return (Width == other.width) && (Height == other.height); // IEquatable<T> public bool Equals(RectangleStruct other) return (Width == other.width) && (Height == other.height); public override int GetHashCode() return Width.GetHashCode() ^ Height.GetHashCode(); c2) c2) static public bool operator ==(RectangleStruct c1, RectangleStruct return c1.equals(c2); static public bool operator!=(rectanglestruct c1, RectangleStruct return!(c1 == c2); (2) Reference type public class RectangleReference : IEquatable<RectangleReference>

double Width; // constructors public RectangleReference() Width = Height = 0.0; public RectangleReference(double width, double height) Width = width; Height = height; // IEquatable public override bool Equals(object obj) // this cannot be null if( obj == null ) // same class? RectangleReference other; if( (Object) (other = obj as RectangleReference)!= null ) return (Width == other.width) && (Height == other.height); // obj is another type // IEquatable<T> public bool Equals(RectangleReference other) // this cannot be null if ((Object)other == null) return (Width == other.width) && (Height == other.height); public override int GetHashCode() return Width.GetHashCode() ^ Height.GetHashCode(); static public bool operator ==(RectangleReference c1, RectangleReference c2) // c1 can be null here if ((Object)c1 == null) return (Object)c2 == null; return c1.equals(c2); static public bool operator!=(rectanglereference c1, RectangleReference c2) return!(c1 == c2);

Summary - Object.Equals() does o A value comparison on value types, i.e. each field must be equal o A reference comparison for reference types, i.e. the referenced objects must be the same. Comparing with null Two null values are considered to be equal A null value compared to a non null value is not equal In short: null is only equal to null - Overriding Object.Equals() o For value types There is a significant performance gain Overloading the Equals() method in case the other object is of the same type even increases performance gain Add : IEquatable<ClassName> to the definition of the class o For reference types If we want to alter the default reference comparison and implement a value type comparison, this is the method we want to override Overloading the Equals() method in case the other object is of the same type gives only a small performance gain but I would still do it Add : IEquatable<ClassName> to the definition of the class o If you override object.equals() then override GetHashCode() also - Use object.equals() if you implement the operators == and!=

Appendix A using System.Collections.Generic; // delegates namespace GregoryAdam.Base.ExtensionMethods public delegate void delegatevoid(); public static partial class ExtensionMethods #region ExecuteTimed private static Stack<DateTime> Times = new Stack<DateTime>(); private static Stack<string> Subject = new Stack<string>(); //------------------------------------------------------------- public static void ExecuteTimed(this delegatevoid function) ExecuteTimed(function, false); bool pause) "()"); public static void ExecuteTimed(this delegatevoid function, Start(function.GetInvocationList()[0].Method.Name + function(); End(pause); //------------------------------------------------------------- private static void Start(string subject) lock (Times) Subject.Push(subject); Times.Push(DateTime.Now); //------------------------------------------------------------- private static void End() End(false); //------------------------------------------------------------- private static void End(bool pause) TimeSpan elapsed; string subject; Stack empty"); lock (Times) if (Times.Count == 0) System.Diagnostics.Debug.Assert(false, "Time

return; elapsed = DateTime.Now - Times.Pop(); subject = Subject.Pop(); Console.WriteLine("0 : 1:00:2:00:3:00.4:00", subject, elapsed.hours, elapsed.minutes, elapsed.seconds, elapsed.milliseconds / 10 ); if (pause) Console.WriteLine("Enter to continue"); Console.ReadLine(); //------------------------------------------------------------- #endregion

Appendix B References (1) Accelerated C# 2008 Apress by Trey Nash (2) Msdn online