Autofixure中Fixture.Customize重载为何返回类型不同?
Customize overload return void (modifying the Fixture instance) while the non-generic overload accepting ICustomization returns IFixture? Great question! This boils down to the distinct design intentions behind these two Customize methods in AutoFixture, which cater to different configuration scenarios:
1. Generic Customize<T>(Func<ICustomizationComposer<T>, ISpecimenBuilder>)
This overload is built for targeted, type-specific configuration. Its sole job is to modify the current Fixture instance's internal rules for creating objects of type T—think of it as tweaking a specific setting directly on the existing fixture.
Since it operates in-place (no new fixture is created), returning void makes sense: you're not getting a new object, you're modifying the one you already have. For example:
var fixture = new Fixture(); // Modifies the fixture's Person configuration directly fixture.Customize<Person>(c => c.With(p => p.Name, "Bob")); // All subsequent Person instances from this fixture will have Name = "Bob" var person = fixture.Create<Person>();
The design here prioritizes clarity over chaining—this is a "side effect" operation that alters the fixture's state, not a method that produces a new instance to chain off of.
2. Non-generic Customize(ICustomization)
This overload is meant for reusable, holistic customization strategies. When you pass an ICustomization (like AutoMoqCustomization or a custom implementation you've written), it applies that entire set of rules to the fixture.
Returning IFixture (specifically, returning this, the current fixture instance) enables fluent chaining, which is useful when you want to combine multiple customizations or follow up with additional configuration in a single line. For example:
var fixture = new Fixture() .Customize(new AutoMoqCustomization()) .Customize(new MyCustomDomainRules());
This design aligns with the fluent interface pattern, making it cleaner to compose multiple configuration steps without breaking the flow.
Why this matters for your fluent inline configuration
If you were hoping to chain generic Customize calls fluently, you'll hit a wall because of the void return type. But there's a workaround if you want inline type-specific configuration that feels fluent: use the Build<T> method instead. It creates a one-off customization for a single object creation (rather than modifying the fixture's global rules) and supports chaining:
var person = new Fixture() .Build<Person>() .With(p => p.Name, "Alice") .Without(p => p.Age) .Create();
If you need global type-specific rules and still want a fluent style, you could wrap the generic Customize calls in an extension method that returns the fixture, like:
public static IFixture CustomizeType<T>(this IFixture fixture, Func<ICustomizationComposer<T>, ISpecimenBuilder> customization) { fixture.Customize(customization); return fixture; }
Then you can chain it:
var fixture = new Fixture() .CustomizeType<Person>(c => c.With(p => p.Name, "Bob")) .Customize(new AutoMoqCustomization());
内容的提问来源于stack exchange,提问作者cocogorilla

