C# IoC:注入对象含条件时的实例化问题咨询
Hey there! Let's walk through how to implement your described instantiation logic—where a Processor uses a Validator to check a Business Object, then instantiates subsequent components only if validation passes—using C# IoC containers. Since you haven't picked a framework yet, I'll cover general best practices plus concrete examples for popular containers like Microsoft.Extensions.DependencyInjection and Autofac.
Core Principles to Follow First
Before diving into code, keep these rules in mind to avoid anti-patterns:
- Avoid Service Locator: Don't hardcode direct calls to the IoC container in your business logic. Use constructor injection or factories instead.
- Decouple Logic: Extract validation and conditional instantiation into dedicated classes (validators, factories, strategies) so your
Processorstays focused on its core job. - Leverage IoC for Dependencies: Let the container manage all component instances—never
newup dependencies directly in yourProcessor.
Approach 1: Factory Pattern (Most Flexible for Dynamic Conditions)
Factories are perfect when you need to create components after validating the Business Object (and possibly based on its properties). The factory uses the IoC container to resolve dependencies, while your Processor just calls the factory.
Step 1: Define Interfaces
// Core interfaces public interface IValidator<TBo> { bool Validate(TBo businessObject); } public interface IProcessor<TBo> { void Process(TBo businessObject); } public interface ISubsequentComponent<TBo> { void Execute(TBo businessObject); } // Factory interface to encapsulate conditional creation public interface ISubsequentComponentFactory<TBo> { ISubsequentComponent<TBo> Create(TBo businessObject); }
Step 2: Implement the Factory
The factory uses the IoC container to resolve the correct ISubsequentComponent based on the Business Object's properties:
public class OrderSubsequentComponentFactory : ISubsequentComponentFactory<OrderBo> { private readonly IServiceProvider _serviceProvider; // Inject the service provider (or container-specific context) public OrderSubsequentComponentFactory(IServiceProvider serviceProvider) { _serviceProvider = serviceProvider; } public ISubsequentComponent<OrderBo> Create(OrderBo businessObject) { // Example: Choose component based on OrderType return businessObject.OrderType switch { OrderType.Normal => _serviceProvider.GetRequiredService<NormalOrderComponent>(), OrderType.Vip => _serviceProvider.GetRequiredService<VipOrderComponent>(), _ => throw new NotSupportedException($"Unsupported order type: {businessObject.OrderType}") }; } }
Step 3: Implement the Processor
Inject the validator and factory into the Processor—no direct container calls here:
public class OrderProcessor : IProcessor<OrderBo> { private readonly IValidator<OrderBo> _validator; private readonly ISubsequentComponentFactory<OrderBo> _componentFactory; public OrderProcessor(IValidator<OrderBo> validator, ISubsequentComponentFactory<OrderBo> componentFactory) { _validator = validator; _componentFactory = componentFactory; } public void Process(OrderBo businessObject) { if (_validator.Validate(businessObject)) { // Create the appropriate component only if validation passes var component = _componentFactory.Create(businessObject); component.Execute(businessObject); } else { // Handle validation failure (log, throw, return error, etc.) throw new InvalidOperationException("Business object failed validation"); } } }
Step 4: Register with IoC Container
Microsoft.Extensions.DependencyInjection:
var services = new ServiceCollection(); // Register core components services.AddScoped<IValidator<OrderBo>, OrderValidator>(); services.AddScoped<IProcessor<OrderBo>, OrderProcessor>(); // Register factory and subsequent components services.AddScoped<ISubsequentComponentFactory<OrderBo>, OrderSubsequentComponentFactory>(); services.AddScoped<NormalOrderComponent>(); services.AddScoped<VipOrderComponent>(); var serviceProvider = services.BuildServiceProvider();
Autofac:
var builder = new ContainerBuilder(); builder.RegisterType<OrderValidator>().As<IValidator<OrderBo>>(); builder.RegisterType<OrderProcessor>().As<IProcessor<OrderBo>>(); builder.RegisterType<OrderSubsequentComponentFactory>().As<ISubsequentComponentFactory<OrderBo>>(); builder.RegisterType<NormalOrderComponent>(); builder.RegisterType<VipOrderComponent>(); var container = builder.Build();
Approach 2: Decorator Pattern (Separate Validation from Processing)
If you want to enforce validation before any processing happens, a decorator wraps your core Processor with validation logic. This keeps validation out of your main processor code.
Example Implementation
// Decorator that adds validation to any IProcessor<TBo> public class ValidatingProcessorDecorator<TBo> : IProcessor<TBo> { private readonly IProcessor<TBo> _innerProcessor; private readonly IValidator<TBo> _validator; public ValidatingProcessorDecorator(IProcessor<TBo> innerProcessor, IValidator<TBo> validator) { _innerProcessor = innerProcessor; _validator = validator; } public void Process(TBo businessObject) { if (!_validator.Validate(businessObject)) { throw new InvalidOperationException("Validation failed"); } // Only call the real processor if validation passes _innerProcessor.Process(businessObject); } } // Core processor (no validation logic here) public class CoreOrderProcessor : IProcessor<OrderBo> { private readonly ISubsequentComponent<OrderBo> _component; public CoreOrderProcessor(ISubsequentComponent<OrderBo> component) { _component = component; } public void Process(OrderBo businessObject) { _component.Execute(businessObject); } }
Registering the Decorator
Microsoft.Extensions.DependencyInjection:
You'll need to register the decorator manually or use a library like Scrutor to simplify:
// Using Scrutor for easy decoration services.AddScoped<IProcessor<OrderBo>, CoreOrderProcessor>(); services.Decorate<IProcessor<OrderBo>, ValidatingProcessorDecorator<OrderBo>>(); services.AddScoped<IValidator<OrderBo>, OrderValidator>(); services.AddScoped<ISubsequentComponent<OrderBo>, OrderSubsequentComponent>();
Autofac:
Autofac has built-in support for decorators:
builder.RegisterType<CoreOrderProcessor>().As<IProcessor<OrderBo>>(); builder.RegisterDecorator<ValidatingProcessorDecorator<OrderBo>, IProcessor<OrderBo>>(); builder.RegisterType<OrderValidator>().As<IValidator<OrderBo>>(); builder.RegisterType<OrderSubsequentComponent>().As<ISubsequentComponent<OrderBo>>();
Approach 3: Conditional Registration (For Static Conditions)
If your component choice is based on a static condition (like environment, config setting, or a fixed property), you can register components conditionally directly in the IoC container.
Example with Microsoft.Extensions.DependencyInjection:
var isProduction = configuration.GetValue<bool>("IsProduction"); services.AddScoped<IValidator<OrderBo>, OrderValidator>(); services.AddScoped<IProcessor<OrderBo>, OrderProcessor>(); // Register different subsequent components based on environment if (isProduction) { services.AddScoped<ISubsequentComponent<OrderBo>, ProductionOrderComponent>(); } else { services.AddScoped<ISubsequentComponent<OrderBo>, DevelopmentOrderComponent>(); }
Final Recommendations
- Start with Factories: They're the most straightforward for dynamic, Business Object-dependent conditions (which sounds like your use case).
- Use Decorators for Cross-Cutting Concerns: Validation is a classic cross-cutting concern, so decorators keep your core processor clean.
- Avoid Overcomplicating: Don't use conditional registration unless your conditions are static—factories handle dynamic cases better.
内容的提问来源于stack exchange,提问作者Peter Lange

