Install
dotnet add package C0deGeek.ObjectCompare --version 1.0.0
| Product | Versions |
|---|---|
| .NET |
README
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 failuresArgumentException: Invalid types or configurationsInvalidOperationException: Operation not supported for typeNotSupportedException: 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
- Reuse
ObjectComparerinstances - Configure appropriate depth limits
- Use custom comparers for complex types
- Enable caching for repeated comparisons
- Handle circular references appropriately
- Use type-specific equality comparers
- Consider memory usage with large object graphs
- Implement proper error handling
- Use logging for troubleshooting
- Test with representative data sets
Contributing
- Fork the repository
- Create a feature branch
- Commit your changes
- Push to the branch
- Create a Pull Request
License
This project is licensed under the MIT License - see the LICENSE.md file for details.
Adoption Assessment
Assess this package against its supported frameworks, license, maintenance signals and dependency graph before making it a project standard.
Compatibility metadata lists 1 target framework; confirm the exact target used by your application.
Related Guides & Workflows
Learn how to evaluate, integrate, or audit this package in your .NET project.