{"id":19991027,"url":"https://github.com/replaysMike/AnyDiff","last_synced_at":"2025-05-04T10:30:58.599Z","repository":{"id":48362315,"uuid":"157817803","full_name":"replaysMike/AnyDiff","owner":"replaysMike","description":"A CSharp (C#) diff library that allows you to diff two objects and get a list of the differences back.","archived":false,"fork":false,"pushed_at":"2024-06-18T01:21:03.000Z","size":222,"stargazers_count":172,"open_issues_count":12,"forks_count":18,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-05-01T18:57:48.993Z","etag":null,"topics":["csharp","csharp-code","diff","difference","difference-between","difference-generator","differences-detected","dotnet-core","dotnet-standard"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/replaysMike.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-11-16T05:36:27.000Z","updated_at":"2025-04-09T07:13:25.000Z","dependencies_parsed_at":"2024-10-12T14:20:39.569Z","dependency_job_id":"3f8321d5-12e7-4668-b427-62dbaebaf77a","html_url":"https://github.com/replaysMike/AnyDiff","commit_stats":{"total_commits":77,"total_committers":5,"mean_commits":15.4,"dds":"0.10389610389610393","last_synced_commit":"9c63f31ef0df28dd882b9357bddada4ff2b05eb7"},"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/replaysMike%2FAnyDiff","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/replaysMike%2FAnyDiff/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/replaysMike%2FAnyDiff/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/replaysMike%2FAnyDiff/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/replaysMike","download_url":"https://codeload.github.com/replaysMike/AnyDiff/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252320065,"owners_count":21729058,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["csharp","csharp-code","diff","difference","difference-between","difference-generator","differences-detected","dotnet-core","dotnet-standard"],"created_at":"2024-11-13T04:51:35.301Z","updated_at":"2025-05-04T10:30:56.831Z","avatar_url":"https://github.com/replaysMike.png","language":"C#","funding_links":[],"categories":["C\\#"],"sub_categories":[],"readme":"# AnyDiff\n[![nuget](https://img.shields.io/nuget/v/AnyDiff.svg)](https://www.nuget.org/packages/AnyDiff/)\n[![nuget](https://img.shields.io/nuget/dt/AnyDiff.svg)](https://www.nuget.org/packages/AnyDiff/)\n[![Build status](https://ci.appveyor.com/api/projects/status/6vxd3cq83kuo4hg1?svg=true)](https://ci.appveyor.com/project/MichaelBrown/anydiff)\n[![Codacy Badge](https://api.codacy.com/project/badge/Grade/a79c138869504a359a064a98aa74908a)](https://www.codacy.com/app/replaysMike/AnyDiff?utm_source=github.com\u0026amp;utm_medium=referral\u0026amp;utm_content=replaysMike/AnyDiff\u0026amp;utm_campaign=Badge_Grade)\n[![Codacy Badge](https://api.codacy.com/project/badge/Coverage/a79c138869504a359a064a98aa74908a)](https://www.codacy.com/app/replaysMike/AnyDiff?utm_source=github.com\u0026utm_medium=referral\u0026utm_content=replaysMike/AnyDiff\u0026utm_campaign=Badge_Coverage)\n\nA CSharp (C#) diff library that allows you to diff two objects and get a list of the differences back.\n\n## Description\n\nAnyDiff works with complex objects of any type, and is great for performing changeset tracking, auditing, or anything else that might require comparing differences between complex objects. Great when combined with AnyClone, as it lets you take a snapshot of the current state of an object and then compare it in the future for changes to it.\n\nIt can even do this for objects that are of different types, though the results may vary depending on how different they are.\n\n## Installation\nInstall AnyDiff from the Package Manager Console:\n```powershell\nPM\u003e Install-Package AnyDiff\n```\n\n## Usage\n\nComparing two objects with no differences:\n```csharp\nusing AnyDiff;\n\nvar object1 = new MyComplexObject(1, \"A string\");\nvar object2 = new MyComplexObject(1, \"A string\");\nvar diff = AnyDiff.Diff(object1, object2);\nAssert.AreEqual(diff.Count, 0);\n```\n\nAlternate extension syntax is also available (we will use this in further examples):\n```csharp\nusing AnyDiff.Extensions;\n\nvar object1 = new MyComplexObject(1, \"A string\");\nvar object2 = new MyComplexObject(1, \"A string\");\nvar diff = object1.Diff(object2);\nAssert.AreEqual(diff.Count, 0);\n```\n\nComparing two objects with a single expected change:\n```csharp\nvar object1 = new MyComplexObject(1, \"A string\");\nvar object2 = new MyComplexObject(1, \"A different string\");\nvar diff = object1.Diff(object2);\nAssert.AreEqual(diff.Count, 1);\n```\n\nComparing objects using custom Type Converters for proper delta detection:\n```csharp\npublic class MyComplexObject\n{\n  public int Id { get; private set; }\n\n  /// \u003csummary\u003e\n  /// Convert a formatted string as a TimeSpan\n  /// \u003c/summary\u003e\n  [TypeConverter(typeof(TimeSpanConverter))]\n  public string StartTime { get; set; }\n\n  public TypeConverterObject(int id, string startTime)\n  {\n    Id = id;\n    StartTime = startTime;\n  }\n}\n\nvar object1 = new MyComplexObject(1, \"04:00:00\");\nvar object2 = new MyComplexObject(1, \"04:05:00\");\nvar diff = object1.Diff(object2);\nAssert.AreEqual(diff.Count, 1);\nAssert.AreEqual(TimeSpan.FromMinutes(5), diff.First().Delta); // difference of 5 minutes\n```\n\n### Ignoring Properties\n\nAnydiff will ignore fields and properties decorated using attributes: `[IgnoreDataMember]`, `[NonSerialized]`, and `[JsonIgnore]`.\nIn addition, you can specify properties to ignore using expression syntax.\nSee [Ignoring Properties and Fields](https://github.com/replaysMike/AnyDiff/wiki/Ignoring-Properties-and-Fields) for more details.\n\nIgnoring by properties explicitly by passing a list of properties via expressions:\n\n```csharp\nvar object1 = new MyComplexObject(1, \"A string\", true);\nvar object2 = new MyComplexObject(2, \"A different string\", true);\nvar diff = object1.Diff(object2, x =\u003e x.Id, x =\u003e x.Name);\nAssert.AreEqual(diff.Count, 0);\n```\n\n### Diff specified properties only\n\nAnyDiff also supports processing of specific properties if you don't want to diff the entire object. This works using the same syntax as ignoring properties but passing a different ComparisonOptions. In the example below, only the properties `Id` and `Name` will be compared.\n\n```csharp\nvar object1 = new MyComplexObject(1, \"A string\", true);\nvar object2 = new MyComplexObject(2, \"A different string\", true);\nvar diff = object1.Diff(object2, ComparisonOptions.All | ComparisonOptions.IncludeList, x =\u003e x.Id, x =\u003e x.Name);\nAssert.AreEqual(diff.Count, 0);\n```\n\n### Comparing Unordered lists\n\nIf you wish to perform a diff that ignores the ordering of data in a collection/list, you can specify that behavior with a ComparisonOptions `AllowCollectionsToBeOutOfOrder` flag as well as the `AllowEqualsOverride`, as seen below.\n\n```csharp\nvar list1 = new List\u003cint\u003e { 1, 2, 3 };\nvar list2 = new List\u003cint\u003e { 1, 3, 2 };\nvar diff = list1.Diff(list2, ComparisonOptions.All | ComparisonOptions.AllowCollectionsToBeOutOfOrder | ComparisonOptions.AllowEqualsOverride);\nAssert.AreEqual(diff.Count, 0);\n```\n\n### Analyzing results\n\nViewing the results of a diff:\n```csharp\nvar diff = object1.Diff(object2);\n\nforeach(var difference in diff)\n{\n  Console.Write($\"Index: {difference.ArrayIndex}\"); // when array elements differ in value\n  Console.Write($\"Delta: {difference.Delta}\"); // when numbers, Dates, Timespans, strings differ in value\n  Console.Write($\"Left: {difference.LeftValue}\"); // the left value being compared\n  Console.Write($\"Right: {difference.RightValue}\"); // the right value being compared\n  Console.Write($\"Property name: {difference.Property}\"); // the name of the field/property\n  Console.Write($\"Property type: {difference.PropertyType}\"); // the type of the field/property\n}\n\n```\n\n### Scenarios supported\n\n  - [x] Circular references\n  - [x] Using TypeConverters to understand data types\n  - [x] Deltas on strings, DateTimes, TimeSpans, numeric types\n  - [x] Comparing arrays, collections, custom collections, dictionaries, hashtables\n  - [x] Comparing collections with different ordering\n  - [x] Complex objects, deep type inspection\n  - [x] Entity Framework objects\n  - [x] IEquatable support\n\n### Using with other libraries\nComparing the difference between the same object at different states, using [AnyClone](https://github.com/replaysMike/AnyClone)\n```csharp\nusing AnyDiff.Extensions;\nusing AnyClone;\n\nvar object1 = new MyComplexObject(1, \"A string\");\nvar object1Snapshot = object1.Clone();\n\nvar diff = object1.Diff(object1Snapshot);\nAssert.AreEqual(diff.Count, 0);\n\n// change something anywhere in the object tree\nobject1.Name = \"A different string\";\n\ndiff = object1.Diff(object1Snapshot);\nAssert.AreEqual(diff.Count, 1);\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FreplaysMike%2FAnyDiff","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FreplaysMike%2FAnyDiff","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FreplaysMike%2FAnyDiff/lists"}