ObjectComparator 3.5.9-preview3
See the version list below for details.
dotnet add package ObjectComparator --version 3.5.9-preview3
NuGet\Install-Package ObjectComparator -Version 3.5.9-preview3
<PackageReference Include="ObjectComparator" Version="3.5.9-preview3" />
<PackageVersion Include="ObjectComparator" Version="3.5.9-preview3" />
<PackageReference Include="ObjectComparator" />
paket add ObjectComparator --version 3.5.9-preview3
#r "nuget: ObjectComparator, 3.5.9-preview3"
#:package ObjectComparator@3.5.9-preview3
#addin nuget:?package=ObjectComparator&version=3.5.9-preview3&prerelease
#tool nuget:?package=ObjectComparator&version=3.5.9-preview3&prerelease
ObjectComparator
Overview
ObjectComparator is a high-performance .NET library crafted meticulously for deep comparisons between objects. Beyond just pointing out the disparities, it delves into the depths of objects, reflecting even the minutest differences. Furthermore, it arms developers with the capability to prescribe custom comparison rules tailored for specific properties or fields.
Key Features
- Deep Comparisons: Unravel every detail and identify even the slightest differences between complex objects.
- Custom Rules: Define bespoke comparison criteria for distinct properties or fields, ensuring you have full control over the comparison process.
- High Performance: Despite the comprehensive nature of its comparisons, ObjectComparator stands out due to its blazing speed.
Table of Contents
- Overview
- Key Features
- Installation
- Usage
- Display Distinctions with Custom Strategy
- Contributing
- License
Installation
NuGet Package Manager Console
Install-Package ObjectComparator
Install with .NET CLI
dotnet add package ObjectComparator
Usage
Basic Comparison
Compare two Student objects and identify the differences.
         var actual = new Student
            {
                Name = "Alex",
                Age = 20,
                Vehicle = new Vehicle
                {
                    Model = "Audi"
                },
                Courses = new[]
                {
                    new Course
                    {
                        Name = "Math",
                        Duration = TimeSpan.FromHours(4)
                    },
                    new Course
                    {
                        Name = "Liter",
                        Duration = TimeSpan.FromHours(4)
                    }
                }
            };
            var expected = new Student
            {
                Name = "Bob",
                Age = 20,
                Vehicle = new Vehicle
                {
                    Model = "Opel"
                },
                Courses = new[]
                {
                    new Course
                    {
                        Name = "Math",
                        Duration = TimeSpan.FromHours(3)
                    },
                    new Course
                    {
                        Name = "Literature",
                        Duration = TimeSpan.FromHours(4)
                    }
                }
            };
                
               var result = actual.DeeplyEquals(expected); 
	       
	/*   
	    Path: "Student.Name":
	    Expected Value :Alex
	    Actually Value :Bob
    
	    Path: "Student.Vehicle.Model":
	    Expected Value :Audi
	    Actually Value :Opel
    
	    Path: "Student.Courses[0].Duration":
	    Expected Value :04:00:00
	    Actually Value :03:00:00
    
	    Path: "Student.Courses[1].Name":
	    Expected Value :Liter
	    Actually Value :Literature 
	*/
	    
Custom Strategies for Comparison
Define specific strategies for comparing properties.
         var result = actual.DeeplyEquals(expected,
                strategy => strategy
                    .Set(x => x.Vehicle.Model, (act, exp) => act.Length == exp.Length)
                    .Set(x => x.Courses[1].Name, (act, exp) => act.StartsWith('L') && exp.StartsWith('L')));  
		    
        /* 
            Path: "Student.Name":
            Expected Value :Alex
            Actually Value :Bob
            
            Path: "Student.Courses[0].Duration":
            Expected Value :04:00:00
            Actually Value :03:00:00
        */
    
Ignoring Specific Properties or Fields
Omit certain properties or fields from the comparison.
    var ignore = new[] {"Name", "Courses", "Vehicle" };
    var result = actual.DeeplyEquals(expected,ignore);
   
     /*
     	Objects are deeply equal
    */
    
Display Distinctions with Custom Strategy
Provide specific strategies and display the differences.
     var result = actual.DeeplyEquals(expected,
                strategy => strategy
                    .Set(x => x.Vehicle.Model, (act, exp) => act.StartsWith('A') && exp.StartsWith('A')), "Name", "Courses");
		    
    /*
		Path: "Student.Vehicle.Model":
		Expected Value :Audi
		Actually Value :Opel
		Details : (act:(Audi), exp:(Opel)) => (act:(Audi).StartsWith(A) AndAlso exp:(Opel).StartsWith(A))
    */
    
    var skip = new[] {"Vehicle", "Name", "Courses[1].Name"};
            var result = expected.DeeplyEquals(actual,
                str => str.Set(x => x.Courses[0].Duration, (act, exp) => act > TimeSpan.FromHours(3),
                    new Display {Expected = "Expected that Duration should be more that 3 hours"}), skip);
		    
    /*	    
		Path: "Student.Courses[0].Duration":
		Expected Value :Expected that Duration should be more that 3 hours
		Actually Value :04:00:00
		Details : (act:(03:00:00), exp:(04:00:00)) => (act:(03:00:00) > 03:00:00)
   */
  
Comparison for Dictionary Types
Identify differences between two dictionary objects.
    var expected = new Library
            {
                Books = new Dictionary<string, Book>
                {
                    ["hobbit"] = new Book {Pages = 1000, Text = "hobbit Text"},
                    ["murder in orient express"] = new Book {Pages = 500, Text = "murder in orient express Text"},
                    ["Shantaram"] = new Book {Pages = 500, Text = "Shantaram Text"}
                }
            };
            var actual = new Library
            {
                Books = new Dictionary<string, Book>
                {
                    ["hobbit"] = new Book {Pages = 1, Text = "hobbit Text"},
                    ["murder in orient express"] = new Book {Pages = 500, Text = "murder in orient express Text1"},
                    ["Shantaram"] = new Book {Pages = 500, Text = "Shantaram Text"},
		    ["Shantaram1"] = new() { Pages = 500, Text = "Shantaram Text" }
                }
            };
            var result = expected.DeeplyEquals(actual);
	    
    /*
		Path: "Library.Books":
		Expected Value: 
		Actual Value: Shantaram1
		Details: Added
		
		Path: "Library.Books[hobbit].Pages":
		Expected Value: 1000
		Actual Value: 1
		
		Path: "Library.Books[murder in orient express].Text":
		Expected Value: murder in orient express Text
		Actual Value: murder in orient express Text1
   */
  
Ignore Strategy
Apply a strategy to ignore certain comparisons based on conditions.
     var act = new Student
            {
                Name = "StudentName",
                Age = 1,
                Courses = new[]
                {
                    new Course
                    {
                        Name = "CourseName"
                    }
                }
            };
      var exp = new Student
            {
                Name = "StudentName1",
                Age = 1,
                Courses = new[]
                {
                    new Course
                    {
                        Name = "CourseName1"
                    }
                }
            };
            var distinctions = act.DeeplyEquals(exp, propName => propName.EndsWith("Name"));
    /*
     	Objects are deeply equal
    */
    
DeeplyEquals if type(not primities and not Anonymous Type) has Overridden Equals method
            var actual = new SomeTest("A");
            var expected = new SomeTest("B");
			
			var result = exp.DeeplyEquals(act);
			
	/*
		Path: "SomeTest":
		Expected Value :ObjectsComparator.Tests.SomeTest
		Actually Value :ObjectsComparator.Tests.SomeTest
		Details : Was used override 'Equals()'
	*/
	
DeeplyEquals if type has Overridden Equality method
	/*	
		Path: "SomeTest":
		Expected Value :ObjectsComparator.Tests.SomeTest
		Actually Value :ObjectsComparator.Tests.SomeTest
		Details : == (Equality Operator)
	*/
Display distinctions for Dictionary type
	var firstDictionary = new Dictionary<string, string>
            {
                {"Key", "Value"},
                {"AnotherKey", "Value"},
            };
        var secondDictionary = new Dictionary<string, string>
            {
                {"Key", "Value"},
                {"AnotherKey", "AnotherValue"},
            };
			
	var result = firstDictionary.DeeplyEquals(secondDictionary)
			 
			 
	/*	
		Path: "Dictionary<String, String>[AnotherKey]":
		Expected Value :Value
		Actually Value :AnotherValue
	*/
	
Comparison for Anonymous Types
Detect differences when dealing with anonymous types.
            var actual = new {Integer = 1, String = "Test", Nested = new byte[] {1, 2, 3}};
	    var expected = new {Integer = 1, String = "Test", Nested = new byte[] {1, 2, 4}};
			
	    var result = exp.DeeplyEquals(act);
			
	/*
		Path: "AnonymousType<Int32, String, Byte[]>.Nested[2]":
		Expected Value :3
		Actually Value :4
	*/
                
Contributing
Contributions are welcome! If you find any issues or have suggestions for improvements, please open an issue or submit a pull request on GitHub.
License
This project is licensed under the Apache-2.0 License. See the LICENSE file for more details.
| Product | Versions Compatible and additional computed target framework versions. | 
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 is compatible. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. | 
| .NET Core | netcoreapp3.0 was computed. netcoreapp3.1 was computed. | 
| .NET Standard | netstandard2.1 is compatible. | 
| MonoAndroid | monoandroid was computed. | 
| MonoMac | monomac was computed. | 
| MonoTouch | monotouch was computed. | 
| Tizen | tizen60 was computed. | 
| Xamarin.iOS | xamarinios was computed. | 
| Xamarin.Mac | xamarinmac was computed. | 
| Xamarin.TVOS | xamarintvos was computed. | 
| Xamarin.WatchOS | xamarinwatchos was computed. | 
- 
                                                    .NETStandard 2.1- Microsoft.CSharp (>= 4.7.0)
- Newtonsoft.Json (>= 13.0.1)
 
- 
                                                    net6.0- Microsoft.CSharp (>= 4.7.0)
- Newtonsoft.Json (>= 13.0.1)
 
NuGet packages (2)
Showing the top 2 NuGet packages that depend on ObjectComparator:
| Package | Downloads | 
|---|---|
| Twileloop.SessionGuard Gives you a reactive event based state management framework that centralises application state and give callbacks on state updates across application. It also allows you to write and read persistant states from an XML encoded defalate compressed file, an ideal solution for having data files | |
| Twileloop.SST A central state management library with features like state history, diffing, undo, redo, and deep state cloning. | 
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated | |
|---|---|---|---|
| 3.6.5 | 296 | 10/23/2025 | |
| 3.6.4 | 873 | 10/7/2025 | |
| 3.6.3 | 313 | 10/2/2025 | |
| 3.6.2 | 300 | 10/1/2025 | |
| 3.6.1 | 6,661 | 4/25/2025 | |
| 3.6.0 | 1,188 | 4/9/2025 | |
| 3.5.9 | 3,856 | 3/9/2025 | |
| 3.5.9-preview8 | 206 | 4/6/2025 | |
| 3.5.9-preview7 | 209 | 3/22/2025 | |
| 3.5.9-preview6 | 207 | 3/22/2025 | |
| 3.5.9-preview5 | 197 | 3/18/2025 | |
| 3.5.9-preview4 | 209 | 3/17/2025 | |
| 3.5.9-preview3 | 183 | 3/12/2025 | |
| 3.5.9-preview2 | 207 | 3/12/2025 | |
| 3.5.9-preview1 | 208 | 3/12/2025 | |
| 3.5.8 | 17,350 | 2/12/2024 | |
| 3.5.7 | 6,442 | 10/9/2023 | |
| 3.5.6 | 631 | 9/27/2023 | |
| 3.5.5 | 887 | 9/16/2023 | |
| 3.5.4 | 584 | 9/16/2023 | |
| 3.5.3 | 1,695 | 7/31/2023 | |
| 3.5.2 | 21,354 | 5/16/2022 | |
| 3.5.1 | 1,080 | 5/14/2022 | |
| 3.5.0 | 104,580 | 4/22/2021 | |
| 3.4.0 | 10,042 | 1/8/2021 | |
| 3.3.0 | 1,152 | 1/8/2021 | |
| 3.2.0 | 1,121 | 12/29/2020 | |
| 3.1.0 | 1,268 | 10/6/2020 | |
| 3.0.0.6 | 1,181 | 5/14/2022 | |
| 3.0.0 | 1,402 | 9/30/2020 | |
| 2.14.0 | 1,161 | 9/9/2020 | |
| 2.13.0 | 1,522 | 4/15/2020 | |
| 2.12.0 | 1,492 | 12/30/2019 | |
| 2.11.0 | 4,233 | 4/15/2019 | |
| 2.10.0 | 1,312 | 4/9/2019 | |
| 2.0.9 | 1,332 | 3/21/2019 | |
| 2.0.8 | 1,439 | 1/11/2019 | |
| 2.0.7 | 1,500 | 12/15/2018 | |
| 2.0.6 | 1,481 | 11/13/2018 | |
| 2.0.5 | 1,424 | 11/12/2018 | |
| 2.0.4 | 1,425 | 11/12/2018 | |
| 2.0.3 | 1,487 | 11/6/2018 | 
Add details when dictionaty length not equalAdd details when dictionary length not equal