GitXplorerGitXplorer
I

EqualityComparer

public
13 stars
5 forks
4 issues

Commits

List of commits on branch master.
Unverified
1947cf1d476793d47ba0d8a7c142c4f169aae476

Merge pull request #6 from Iristyle/collections

IIristyle committed 12 years ago
Unverified
5d2b7b92376d8171afa8fc8a01a8bfc1e75e31b8

EditorConfig - All files reformatted as 2 spaces

IIristyle committed 12 years ago
Unverified
62084ca18a6f12421660940f74424308cf84fea3

Added standard 2 space EditorConfig with CRLF

IIristyle committed 12 years ago
Unverified
0cc745895a5276b6452de424b71934e1a92fc680

BUGFIX: Properly handle IEnumerable<KeyValuePair<,>>

IIristyle committed 12 years ago
Unverified
87b6b9961845512d94cbfa122d94dd9f461d531c

Added note about .NET 4.5

IIristyle committed 12 years ago
Unverified
41c173cd0eb3233999887428cefd76585ada864f

Merge pull request #5 from corkupine/failingdicttest

IIristyle committed 12 years ago

README

The README file for this repository.

Logo

EqualityComparer

A super basic way of comparing object instances on a property by property / member by member basis. There are allowances for overriding default comparison behaviors, and it's mostly implemented using Expressions.

The code was heavily inspired / derived from Marc Gravells original post on StackOverflow discussing a basic comparison method for DTOs. Like Marcs original post, this code also uses some caching of built Expression trees once an object type has been 'seen'.

This variant is a little more general purpose with a few more features, and is designed primarily around testing semantics.

Installation

  • Install-Package EqualityComparer

Requirements

  • .NET Framework 4+ Client Profile

Usage Examples

There are plenty of examples in the Tests project. Look there for more details.

Should work properly with:

  • Nested types
  • Anonymous types
  • Custom hand-rolled comparers (derived from IEqualityComparer or using the included Func<T,T> based GenericEqualityComparer)
  • Fuzzy date comparison (i.e. where Redis stores an inexact date value vs what .NET has)

Basic Comparison

  Guid sharedGuid = Guid.NewGuid();
  DateTime now = DateTime.Now;
  Assert.True(MemberComparer.Equal(new { PropertyA = "A", Integer = 23, Guid = sharedGuid, Date = now },
    new { PropertyA = "A", Integer = 23, Guid = sharedGuid, Date = now }));

Fuzzy date comparisons.

  DateTime one = DateTime.Parse("07:27:15.01"),
  two = DateTime.Parse("07:27:15.49");

  var a = new { Foo = 5, Bar = new { Now = one } };
  var b = new { Foo = 5, Bar = new { Now = two } };

  Assert.True(MemberComparer.Equal(one, two, new[] { new DateComparer(DateComparisonType.TruncatedToSecond) }));

Custom Comparer

  class ClassWithFieldsAndProperties
  {
    public string Foo;
    public string Bar { get; set; }
  }

  string Bar = "bar";
  Assert.True(MemberComparer.Equal(new { Integer = 5, Custom = new ClassWithFieldsAndProperties() { Foo = "456", Bar = Bar } },
    new { Integer = 5, Custom = new ClassWithFieldsAndProperties() { Foo = "4567", Bar = Bar } },
    new[] { new GenericEqualityComparer<ClassWithFieldsAndProperties>((a, b) => a.Bar == b.Bar) }));

GenericEqualityComparer

In addition to being able to create a new instance of a GenericEqualityComparer with an anonymous Func<T,T,bool>, the GenericEqualityComparer class has a ByAllMembers static which will recursively examine the type and generate a (cached) comparison Expression.

Given this class:

  class A
  {
    public A(int integer, string @string)
    {
      Integer = integer;
      String = @string;
    }

    public int Integer { get; set; }
    public string String { get; set; }

    public static GenericEqualityComparer<A> IntegerOnlyComparer = new GenericEqualityComparer<A>((a1, a2) => a1.Integer == a2.Integer);
  }

We can use the standard ByAllMembers comparison.

  A a = new A(3, "Foo"),
  b = new A(3, "Foo");

  Assert.Equal(a, b, GenericEqualityComparer<A>.ByAllMembers());

ByAllMembers also has an overload that lets you specify comparers to use when a specific type is encountered. In this example, we tell it to only look at the Integer member of A when A instances are found in the object graph.

  class B
  {
    public B(int integer, A a)
    {
      Integer = integer;
      A = @a;
    }

    public int Integer { get; set; }
    public A A { get; set; }
  }

  B b = new B(6, new A(5, "Foo")),
  b2 = new B(6, new A(5, "Bar"));

  Assert.Equal(b, b2, GenericEqualityComparer<B>.ByAllMembers(new[] { A.IntegerOnlyComparer }));

Similar Projects

  • AutoFixture includes a library called Ploeh.SemanticComparison . I haven't checked out all the details, but it does pack a Fluent interface.
  • AnonymousComparer - the AnonymousComparer looks very similar to the GenericEqualityComparer class in our library, except for some syntactical differences. It doesn't look like there are options to override the behavior of comparisons either.
  • System.DataStructures.FuncComparer - looks like a basic implementation of a Func<T,T,bool> IEqualityComparer.

Future Improvements

  • Ensure Mono works properly (it should already)

Contributing

Fork the code, and submit a pull request!

Any useful changes are welcomed. If you have an idea you'd like to see implemented that strays far from the simple spirit of the application, ping us first so that we're on the same page.

Credits

Creative Commons icon courtesy WikiMedia