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
+73Lines changed: 73 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -87,6 +87,79 @@ All remaining parameters (after those satisfied by inline/member data) are popul
87
87
> **Note:**
88
88
> NSubstitute is used when the type being created is an interface or abstract class.
89
89
90
+
### Frozen Reuse Scenarios
91
+
92
+
When you decorate a parameter with `[Frozen]`, its resolved instance is reused for any other specimens needing that type. The `MemberAutoNSubstituteData` attribute supports an additional convenience: **exact-type promotion** of an earlier supplied value to a later `[Frozen]` parameter whose slot was not part of the supplied member row.
93
+
94
+
| Scenario | Attribute | Behavior |
95
+
|----------|-----------|----------|
96
+
| Positional frozen reuse |`ClassAutoNSubstituteData` + `MemberAutoNSubstituteData`| If the data row supplies a value at the same parameter index as a `[Frozen]` parameter, that value is frozen and reused. |
97
+
| Exact-type promotion (member data only) |`MemberAutoNSubstituteData`| If a later `[Frozen] T` parameter has no supplied value (index beyond row length), we look for an earlier supplied value whose parameter type is exactly `T` and freeze it. |
98
+
| No interface/base promotion | Both | We do NOT promote across interface or base types—only exact parameter type matches. |
99
+
100
+
#### 1. Positional Reuse
101
+
102
+
```csharp
103
+
[Theory]
104
+
[InlineAutoNSubstituteData(42)]
105
+
publicvoidPositional_Frozen_Reuses_Inline_Value(
106
+
[Frozen] intnumber, // inline supplies index 0 -> frozen
107
+
SomeConsumerconsumer) // receives the same number if it depends on it
newobject?[] { newDualImpl() } // supplies IFoo parameter only
143
+
};
144
+
145
+
[Theory]
146
+
[MemberAutoNSubstituteData(nameof(DualRow))]
147
+
publicvoidDifferent_Interface_Not_Promoted(
148
+
IFoofoo, // supplied DualImpl
149
+
[Frozen] IBarbar, // exact-type mismatch (IBar vs IFoo) -> NOT reused
150
+
UsesBarconsumer)
151
+
{
152
+
bar.Should().NotBeSameAs(foo); // separate instance
153
+
consumer.Bar.Should().BeSameAs(bar); // consumer wired to frozen IBar
154
+
}
155
+
```
156
+
157
+
Design Rationale:
158
+
159
+
- Class data is typically authored with full positional intent—implicit promotion could hide mistakes.
160
+
- Member data commonly supplies only a prefix, so exact-type promotion avoids boilerplate duplication while staying predictable.
161
+
- Restricting to exact type (no interface/base assignability) prevents accidental cross-interface freezes (e.g., a dual-implemented object hijacking a different abstraction).
0 commit comments