You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: README.md
+79Lines changed: 79 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -12,6 +12,7 @@ Writing correct equality logic in C# is tedious, error-prone, and easy to forget
12
12
-**Highly customizable** — Use `[CustomEquality]`, `[StringEquality]`, `[PrecisionEquality]`, `[ReferenceEquality]`, or `[IgnoreEquality]` to control comparison per-property.
13
13
-**Works everywhere** — Supports classes, structs, records, and record structs.
14
14
-**Inheritance-friendly** — Correctly chains `base.Equals()` across deep inheritance hierarchies and inherits equality attributes from overridden properties.
15
+
-**Structured diffs** — Call `Inequalities()` to get exactly which members differ between two instances, with full paths into nested objects, collections, and dictionaries.
15
16
-**Compile-time only** — No reflection or IL injection. The generator emits plain C# source code that you can inspect and debug.
16
17
17
18
----------------
@@ -292,6 +293,84 @@ partial class Doctor : Person
292
293
}
293
294
```
294
295
296
+
## Inequalities
297
+
298
+
Every `[Equatable]` type gets a generated `EqualityComparer` with an `Inequalities()` method that returns exactly which members differ between two instances — with full member paths, including nested objects, collection indices, and dictionary keys.
Addresses["home"].Street: 123 Main St → 121 Main St
339
+
```
340
+
341
+
### How it works
342
+
343
+
`Inequalities()` returns `IEnumerable<Inequality>`, where each `Inequality` has:
344
+
345
+
-**`Path`** — a `MemberPath` describing which member differs (e.g., `Addresses["home"].Street`)
346
+
-**`Left`** — the value from the first object
347
+
-**`Right`** — the value from the second object
348
+
349
+
Paths are composed of segments:
350
+
351
+
| Segment | Example | Meaning |
352
+
|---------|---------|---------|
353
+
|`Property`|`Name`| A property differs |
354
+
|`Field`|`_count`| A field differs |
355
+
|`Index`|`[0]`| An ordered collection element at index |
356
+
|`Key`|`["home"]`| A dictionary entry by key |
357
+
|`Added`|`[+]`| An element present only in the right set |
358
+
|`Removed`|`[-]`| An element present only in the left set |
359
+
360
+
### Drill-down
361
+
362
+
When a collection element or dictionary value is itself an `[Equatable]` type, `Inequalities()` automatically drills down into its properties instead of reporting the entire object as changed. In the example above, the address change is reported as `Addresses["home"].Street` rather than the whole `Address` object.
363
+
364
+
### Base path
365
+
366
+
You can pass a base path to prefix all reported paths — useful when composing inequalities from parent contexts:
0 commit comments