You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C# IoC:注入对象含条件时的实例化问题咨询

Handling Conditional Instantiation in C# IoC for Your Processor/Validator Flow

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 Processor stays focused on its core job.
  • Leverage IoC for Dependencies: Let the container manage all component instances—never new up dependencies directly in your Processor.

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 03:42:36