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

如何实例化类时仅传入构造函数中非注入服务的参数?

几种可行的实现方案

方案1:服务定位器模式(简单直接,但要注意作用域)

可以搞个静态的服务容器持有者,在程序启动时把DI容器传进去,然后Game的构造函数里直接从这个持有者拿ISessionsRepository实例。

代码示例:

// 先整个静态类存服务容器
public static class ServiceLocator
{
    public static IServiceProvider? Provider { get; set; }
}

// 修改Game类的构造函数
public class Game 
{
    private ISessionsRepository repo;

    public Game(string sessionID, string sessionName) 
    {
        // 从服务定位器里拿依赖
        repo = ServiceLocator.Provider?.GetRequiredService<ISessionsRepository>() 
            ?? throw new InvalidOperationException("服务容器还没初始化呢");
        // 你的业务逻辑
    }
}

然后在程序启动的时候(比如ASP.NET Core的Program.cs)初始化这个静态类:

var builder = WebApplication.CreateBuilder(args);
// 先把ISessionsRepository的实现注册到DI里
builder.Services.AddScoped<ISessionsRepository, SessionsRepository>();

var app = builder.Build();
// 把DI容器传给ServiceLocator
ServiceLocator.Provider = app.Services;

app.Run();

要提醒下:如果ISessionsRepository是Scoped作用域的服务,直接从根容器拿可能会有生命周期问题——比如在请求外创建Game实例的话,拿到的Scoped实例不会自动释放。所以最好在正确的作用域里创建Game,或者把依赖改成Transient的。

方案2:静态注入(适合单例/瞬态依赖)

如果你的ISessionsRepository是单例或者瞬态的,可以提前把实例注入到Game的静态字段里,然后构造函数直接用这个静态实例。

代码示例:

public class Game 
{
    private static ISessionsRepository? _staticRepo;
    private ISessionsRepository repo;

    // 整个静态方法用来注入依赖
    public static void SetRepository(ISessionsRepository repo)
    {
        _staticRepo = repo ?? throw new ArgumentNullException(nameof(repo));
    }

    public Game(string sessionID, string sessionName) 
    {
        repo = _staticRepo ?? throw new InvalidOperationException("Repository还没初始化");
        // 你的业务逻辑
    }
}

启动的时候初始化:

var repo = app.Services.GetRequiredService<ISessionsRepository>();
Game.SetRepository(repo);

这种方式比服务定位器更简单,但只适合依赖是单例的场景,灵活性差点。

方案3:工厂类(更符合DI设计原则)

要是不想用静态或者服务定位器,可以整个Game工厂,工厂由DI管理,通过工厂来创建Game实例——虽然不是直接new Game(...),但可以封装得差不多。

代码示例:

// 先定义工厂接口
public interface IGameFactory
{
    Game Create(string sessionID, string sessionName);
}

// 实现工厂,工厂自己从DI拿ISessionsRepository
public class GameFactory : IGameFactory
{
    private readonly ISessionsRepository _repo;

    public GameFactory(ISessionsRepository repo)
    {
        _repo = repo;
    }

    public Game Create(string sessionID, string sessionName)
    {
        return new Game(_repo, sessionID, sessionName);
    }
}

// 把Game的原构造函数改成internal,防止外部直接调用
public class Game 
{
    private ISessionsRepository repo;

    internal Game(ISessionsRepository injectedRepo, string sessionID, string sessionName) 
    {
        repo = injectedRepo;
        // 你的业务逻辑
    }
}

然后把工厂注册到DI:

builder.Services.AddScoped<IGameFactory, GameFactory>();

用的时候先从DI拿工厂,再创建实例:

// 在需要创建Game的地方,先获取IGameFactory
var gameFactory = serviceProvider.GetRequiredService<IGameFactory>();
Game game = gameFactory.Create("1", "name");

这种方式更符合依赖注入的设计思想,没有静态依赖,但需要通过工厂来创建。要是嫌麻烦,还能在Game类里整个静态的Create方法,内部调用工厂,这样调用起来就和直接new差不多了。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 19:27:25