C0deGeek.ObjectCompare 1.0.0

There is a newer version of this package available.
See the version list below for details.
dotnet add package C0deGeek.ObjectCompare --version 1.0.0                
NuGet\Install-Package C0deGeek.ObjectCompare -Version 1.0.0                
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="C0deGeek.ObjectCompare" Version="1.0.0" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add C0deGeek.ObjectCompare --version 1.0.0                
#r "nuget: C0deGeek.ObjectCompare, 1.0.0"                
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install C0deGeek.ObjectCompare as a Cake Addin
#addin nuget:?package=C0deGeek.ObjectCompare&version=1.0.0

// Install C0deGeek.ObjectCompare as a Cake Tool
#tool nuget:?package=C0deGeek.ObjectCompare&version=1.0.0                

ObjectComparison

A high-performance, extensible .NET library for deep object comparison with support for complex types, collections, and dynamic objects.

Features

  • Deep comparison of objects with circular reference detection
  • Object snapshot capability with intelligent cloning
  • Support for custom comparison and cloning logic
  • Collection comparison with order-sensitive and order-insensitive modes
  • Dynamic object comparison support (ExpandoObject, DynamicObject)
  • Floating-point comparison with configurable precision
  • Advanced type handling:
    • Nullable types
    • Value types with safe default initialization
    • Reference types with proper null handling
    • Custom type cloning
  • Thread-safe caching:
    • Type metadata caching
    • Expression compilation caching
    • Property access optimization
  • Comprehensive comparison results with detailed differences
  • Expression tree-based property access for performance
  • Support for private field comparison
  • Configurable maximum depth and object count limits

Installation

dotnet add package ObjectComparison

Quick Start

// Create a comparer with default configuration
var comparer = new ObjectComparer();

// Compare two objects
var result = comparer.Compare(obj1, obj2);

if (!result.AreEqual)
{
    foreach (var difference in result.Differences)
    {
        Console.WriteLine(difference);
    }
}

// Take a snapshot for later comparison
var snapshot = comparer.TakeSnapshot(originalObject);

Object Snapshots

The library provides powerful snapshot capabilities with intelligent cloning.

Basic Snapshot Usage

// Create an object and take a snapshot
var person = new Person
{
    Name = "John Doe",
    Age = 30,
    Hobbies = new List<string> { "Reading", "Gaming" }
};

var comparer = new ObjectComparer();
var snapshot = comparer.TakeSnapshot(person);

// Make changes to the original object
person.Age = 31;
person.Hobbies.Add("Cooking");

// Compare current state with snapshot
var result = comparer.Compare(person, snapshot);

Custom Type Cloning

var config = new ComparisonConfig
{
    CustomCloners = new Dictionary<Type, Func<object, object>>
    {
        { 
            typeof(DateTime), 
            obj => ((DateTime)obj).Date // Clone only the date part
        },
        {
            typeof(StringBuilder),
            obj => new StringBuilder(((StringBuilder)obj).ToString())
        }
    }
};

var comparer = new ObjectComparer(config);

Type Handling

// Value Types
struct Point { public int X, Y; }
var point = new Point { X = 1, Y = 2 };
var snapshot = comparer.TakeSnapshot(point); // Creates proper value copy

// Nullable Types
int? nullableValue = 42;
var snapshot = comparer.TakeSnapshot(nullableValue); // Preserves null state

// Collections
var list = new List<Point> { new() { X = 1, Y = 2 } };
var snapshot = comparer.TakeSnapshot(list); // Deep clones elements

Advanced Configuration

var config = new ComparisonConfig
{
    // Comparison Options
    ComparePrivateFields = true,
    DeepComparison = true,
    IgnoreCollectionOrder = true,
    
    // Precision Settings
    DecimalPrecision = 4,
    FloatingPointTolerance = 1e-10,
    UseRelativeFloatingPointComparison = true,
    
    // Null Handling
    NullValueHandling = NullHandling.Loose,
    
    // Performance Options
    MaxDepth = 10,
    MaxObjectCount = 10000,
    UseCachedMetadata = true,
    
    // Property Options
    ExcludedProperties = new HashSet<string> { "CachedValue", "LastModified" },
    CompareReadOnlyProperties = true,
    
    // Type-Specific Options
    CustomComparers = new Dictionary<Type, ICustomComparer>(),
    CollectionItemComparers = new Dictionary<Type, IEqualityComparer>(),
    
    // Diagnostics
    TrackPropertyPaths = true,
    Logger = loggerFactory.CreateLogger<ObjectComparer>()
};

Error Handling

try
{
    var result = comparer.Compare(obj1, obj2);
}
catch (ComparisonException ex) when (ex.Path != null)
{
    Console.WriteLine($"Comparison failed at path: {ex.Path}");
    Console.WriteLine($"Error: {ex.Message}");
}
catch (ArgumentException ex)
{
    Console.WriteLine($"Invalid argument: {ex.Message}");
}

Common Exceptions

  • ComparisonException: General comparison failures
  • ArgumentException: Invalid types or configurations
  • InvalidOperationException: Operation not supported for type
  • NotSupportedException: Unsupported type or operation

Performance Optimization

Caching

// Enable all caching features
var config = new ComparisonConfig
{
    UseCachedMetadata = true,
    TrackPropertyPaths = false // Disable for better performance
};

// Pre-compile frequently used types
TypeCache.GetMetadata(typeof(MyFrequentType), true);

Memory Management

// Limit object graph traversal
var config = new ComparisonConfig
{
    MaxDepth = 5,
    MaxObjectCount = 1000,
    ExcludedProperties = new HashSet<string> { "LargeCollection", "CachedData" }
};

Collection Handling

// Fast collection comparison for simple types
var config = new ComparisonConfig
{
    IgnoreCollectionOrder = true, // Uses optimized comparison
    CollectionItemComparers = new Dictionary<Type, IEqualityComparer>
    {
        { typeof(int), EqualityComparer<int>.Default }
    }
};

Thread Safety

The library uses several thread-safe mechanisms:

  • Concurrent collections for caches
  • Immutable configuration objects
  • Thread-local contexts for comparison state
  • Lock-free algorithms where possible

Safe Concurrent Usage

// Create once and reuse
private static readonly ObjectComparer SharedComparer = new();

// Safe for concurrent use
public async Task CompareAsync(object obj1, object obj2)
{
    await Task.Run(() => SharedComparer.Compare(obj1, obj2));
}

Best Practices

  1. Reuse ObjectComparer instances
  2. Configure appropriate depth limits
  3. Use custom comparers for complex types
  4. Enable caching for repeated comparisons
  5. Handle circular references appropriately
  6. Use type-specific equality comparers
  7. Consider memory usage with large object graphs
  8. Implement proper error handling
  9. Use logging for troubleshooting
  10. Test with representative data sets

Contributing

  1. Fork the repository
  2. Create a feature branch
  3. Commit your changes
  4. Push to the branch
  5. Create a Pull Request

License

License: MIT
This project is licensed under the MIT License - see the LICENSE.md file for details.

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
1.0.1 74 11/6/2024
1.0.0 79 11/1/2024