You need to enable JavaScript to run this app. 使用GetRequiredService获取ViewModel时如何传入自定义参数并保留依赖注入
优惠活动
大模型
产品
解决方案
定价
更多

使用GetRequiredService获取ViewModel时如何传入自定义参数并保留依赖注入

问题说明

当前使用 Microsoft.Extensions.DependencyInjection 5.0.1 版本,核心需求为:从DI容器解析带有自动注入依赖的ViewModel实例,同时支持传入自定义构造参数。
具体场景:

  • ThemeManagementPage 构造时会接收到外部传入的 int 类型参数 param1
  • ThemeManagementViewModel 构造时需要自动从DI容器注入 IResourceService 依赖,同时接收 param1 参数
  • 现有直接通过 Startup.ServiceProvider.GetRequiredService<ThemeManagementViewModel>() 获取实例的方式,无法传入自定义的 param1 参数。
现有代码片段

页面代码

public class ThemeManagementPage : HeadingView
{
    private readonly ThemeManagementViewModel _vm;
    public ThemeManagementPage(int param1)
    {
        // 此处需要将param1传递给ViewModel,同时让DI自动注入IResourceService依赖
        BindingContext  = _vm = 
            Startup.ServiceProvider.GetRequiredService<ThemeManagementViewModel>();
    }
}

public partial class ThemeManagementViewModel : BaseViewModel
{
    private readonly IResourceService _resourceService;
    public ThemeManagementViewModel(IResourceService resourceService, int param1)
    {
        _resourceService = resourceService;
        var x = param1;
    }
}

DI注册代码

public partial class ResourceService : IResourceService
{
    private IDatabaseService _databaseService;
    public ResourceService(IDatabaseService databaseService)
    {
        _databaseService = databaseService;
    }
}

public interface IResourceService
{
    void SetResourceColors();
}

public static class Startup
{
    public static IServiceProvider ServiceProvider { get; set; }
    public static IServiceProvider Init()
    {
        var serviceProvider = new ServiceCollection().ConfigureServices()
            .BuildServiceProvider();
        ServiceProvider = serviceProvider;
        return serviceProvider;
    }
}

public static class DependencyInjectionContainer
{
    public static IServiceCollection ConfigureServices(this IServiceCollection services)
    {
        services.AddSingleton<IDatabaseService, DatabaseService>();
        services.AddSingleton<IResourceService, ResourceService>();
        services.AddTransient<ThemeManagementViewModel>();
        return services;
    }
}
实现方案

方案1:使用内置 ActivatorUtilities 解析(最小改动,无注册逻辑调整)

DI框架从3.0版本开始就内置了 ActivatorUtilities 工具,专门解决混合参数的实例创建场景:构造函数中的参数,能从DI容器解析的自动按生命周期取出,剩余匹配不上的参数用手动传入的实参匹配,完全不需要修改现有的DI注册逻辑。该方法随 Microsoft.Extensions.DependencyInjection 5.0 版本内置,不需要额外安装NuGet包。

修改 ThemeManagementPage 的构造函数逻辑,将原来直接获取服务的代码替换为 ActivatorUtilities.CreateInstance 调用:

public class ThemeManagementPage : HeadingView
{
    private readonly ThemeManagementViewModel _vm;
    public ThemeManagementPage(int param1)
    {
        // 自动从DI容器解析IResourceService依赖,手动传入param1作为自定义构造参数
        BindingContext = _vm = ActivatorUtilities.CreateInstance<ThemeManagementViewModel>(
            Startup.ServiceProvider,
            param1
        );
    }
}

方案优势:

  • 原有 services.AddTransient<ThemeManagementViewModel>(); 注册逻辑完全保留,不需要调整
  • 所有已注册的依赖(包括 IResourceService 本身依赖的 IDatabaseService)都会按原有生命周期正确解析,不会出现依赖脱节的问题
  • 后续如果 ThemeManagementViewModel 新增了需要DI自动注入的构造参数,不需要修改任何调用逻辑,ActivatorUtilities 会自动从容器解析新增的依赖。

方案2:工厂委托注册(适合多参数的复杂场景)

如果后续有大量ViewModel需要传递自定义构造参数,可以将ViewModel的注册逻辑替换为工厂委托形式,在注册时预绑定需要自动注入的依赖,返回一个可以接收自定义参数的委托。

修改DI注册逻辑:

public static IServiceCollection ConfigureServices(this IServiceCollection services)
{
    services.AddSingleton<IDatabaseService, DatabaseService>();
    services.AddSingleton<IResourceService, ResourceService>();
    // 注册工厂委托:自动获取需要注入的IResourceService,返回接收param1的构造委托
    services.AddTransient<Func<int, ThemeManagementViewModel>>(serviceProvider =>
    {
        var resourceService = serviceProvider.GetRequiredService<IResourceService>();
        return (param1) => new ThemeManagementViewModel(resourceService, param1);
    });
    return services;
}

在页面中获取实例时,先拿到工厂委托,再传入自定义参数:

public ThemeManagementPage(int param1)
{
    var vmFactory = Startup.ServiceProvider.GetRequiredService<Func<int, ThemeManagementViewModel>>();
    BindingContext = _vm = vmFactory(param1);
}

方案注意点:

这种方式需要手动维护ViewModel构造函数的参数映射,后续ViewModel新增需要注入的依赖时,需要同步修改工厂委托的逻辑,容易出现遗漏。更适合参数结构稳定、有统一管理需求的场景。

避坑提醒

不要使用硬编码的手动构造方式,比如直接写 new ThemeManagementViewModel(serviceProvider.GetRequiredService<IResourceService>(), param1) 来创建实例,这种写法在ViewModel后续新增构造依赖时,需要同步修改所有手动创建的位置,维护成本极高。


内容的提问来源于stack exchange,提问作者Richard A

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.11.05 18:06:04