VContainer-registering/register-factory | 注册——注册工厂

VContainer 通常在被首次解析时才构建依赖对象(注册实例 除外)。如需精细控制依赖创建时机,可注册工厂方法。

工厂方法本质是 Func<> 委托,可像普通依赖一样被解析。用于在任意时刻创建对象。

:::note
虽然叫"工厂",但实际可以返回已存在的对象。这在需要为同类型配置不同实例时很有用,例如为本地多人游戏中每个玩家创建独立控制器。
:::

以下示例中依赖解析仅发生一次。在 Create() 方法中不会自动触发解析(这是构造函数的工作),但可通过 IObjectResolver API 手动解析。

class FooFactory
{
    public FooFactory(DependencyA dependencyA)
    {
        this.dependencyA = dependencyA;
    }

    public Foo Create(int b) => new Foo(b, dependencyA);
}
builder.Register<FooFactory>(Lifetime.Singleton); // 注册

// ...

var factory = container.Resolve<FooFactory>(); // 触发依赖解析

// ...

var foo1 = factory.Create(1); // 无需解析
var foo2 = factory.Create(2); // 无需解析
var foo3 = factory.Create(3); // 无需解析

对于简单场景,可直接用 lambda 表达式 进行注册。

:::caution
VContainer 不会自动管理工厂返回对象的生命周期。若工厂返回可销毁对象(即实现了 IDisposable 接口的对象),需自行处理。此时推荐使用工厂类,因为工厂本身会被 VContainer 管理并自动销毁(若实现 IDisposable)。
:::

注册仅在运行时需要参数的 Func<> 工厂

无其他依赖的工厂可这样注册:

builder.RegisterFactory<int, Foo>(x => new Foo(x));

使用方法如下:

class ClassA
{
    readonly Func<int, Foo> factory;

    public ClassA(Func<int, Foo> factory)
    {
        this.factory = factory;
    }

    public void DoSomething()
    {
        var foo = factory(100);
        // ...
    }
}

注册需要容器依赖的 Func<> 工厂

如果工厂方法确实需要其他依赖项,则需要为其提供 IObjectResolver。为此,可以注册一个 Func<>, 该Func<>接受一个 IObjectResolver 并返回实际想要使用的的 Func<>

builder.RegisterFactory<int, Foo>(container => // container 是一个 IObjectResolver
{
    var dependency = container.Resolve<Dependency>(); // 一个作用域内对应一次解析
    return x => new Foo(x, dependency); // 每次调用工厂时执行
}, Lifetime.Scoped);

此方式需要 Lifetime 参数来指定内部 Func<> 生成的频率,即外部 Func<> 被调用的频率。

使用方式与简单工厂一致:

class ClassA
{
    readonly Func<int, Foo> factory;

    public ClassA(Func<int, Foo> factory)
    {
        this.factory = factory;
    }

    public void DoSomething()
    {
        var foo = factory.Invoke(100);
        // ...
    }
}

IObjectResolver 的扩展方法在工厂中很有用:

builder.RegisterFactory<CharacterType, CharacterActor>(container =>
{
    return characterType =>
    {
        var characterPrefab = ...
        return container.Instantiate(characterPrefab, parentTransform);
    }
}, Lifetime.Scoped);

更多信息参阅 容器 API

:::note
使用 lambda 函数进行 Func<> 注册是常见情况的简写。在复杂场景中,考虑定义并注册自己的工厂类。
:::

注册工厂方法

工厂可以注册为任何可以转换为 Func<> 的委托,包括类方法。这样,无论底层实现多么复杂,所有工厂都可以作为 Func<> 使用。以下是实现方式。

假设有这个类...

class FooFactory
{
    public FooFactory(DependencyA dependencyA)
    {
        this.dependencyA = dependencyA;
    }

    public Foo Create(int b) => new Foo(b, dependencyA);
}

以下可以使用 FooFactory 作为 Func<>处理,而无需了解或关心完整的类。

builder.Register<FooFactory>(Lifetime.Singleton);
builder.RegisterFactory(container => container.Resolve<FooFactory>().Create, Lifetime.Singleton);

// ...

var factory = container.Resolve<Func<int, Foo>>();

var foo1 = factory(1);
var foo2 = factory(2);
var foo3 = factory(3);

var originalFactoryObject = container.Resolve<FooFactory>(); // 如果需要,工厂对象仍然存在。
// 如果 FooFactory 实现了 IDisposable,那么它将在 IObjectResolver 被释放时调用。
posted @   凌雪寒  阅读(6)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
· 三行代码完成国际化适配,妙~啊~
点击右上角即可分享
微信分享提示