VContainer-registering/register-type | 注册——注册纯 C# 类型

有多种方式可以使用 Register。以以下复杂类型为例:

class ServiceA : IServiceA, IInputPort, IDisposable { /* ... */ }

注册具体类型

builder.Register<ServiceA>(Lifetime.Singleton);

可以这样解析:

class ClassA
{
    public ClassA(ServiceA serviceA) { /* ... */ }
}

注册为接口

builder.Register<IServiceA, ServiceA>();

可以这样解析:

class ClassA
{
    public ClassA(IServiceA serviceA) { /* ... */ }
}

注册为多个接口

builder.Register<ServiceA>(Lifetime.Singleton)
    .As<IServiceA, IInputPort>();

可以这样解析:

class ClassA
{
    public ClassA(IServiceA serviceA) { /* ... */ }
}

class ClassB
{
    public ClassB(IInputPort inputPort) { /* ... */ }
}

自动注册所有实现的接口

builder.Register<ServiceA>(Lifetime.Singleton)
    .AsImplementedInterfaces();

可以这样解析:

class ClassA
{
    public ClassA(IServiceA serviceA) { /* ... */ }
}

class ClassB
{
    public ClassB(IInputPort inputPort) { /* ... */ }
}

注册所有实现的接口和具体类型

builder.Register<ServiceA>(Lifetime.Singleton)
    .AsImplementedInterfaces()
    .AsSelf();

可以这样解析:

class ClassA
{
    public ClassA(IServiceA serviceA) { /* ... */ }
}

class ClassB
{
    public ClassB(IInputPort inputPort) { /* ... */ }
}

class ClassC
{
    public ClassC(ServiceA serviceA) { /* ... */ }
}

注册生命周期接口

class GameController : IStartable, ITickable, IDisposable { /* ... */ }
builder.RegisterEntryPoint<GameController>();

:::note
这类似于 Register<GameController>(Lifetime.Singleton).AsImplementedInterfaces()。与普通接口注册的区别在于它是否在 PlayerLoopSystem 中运行。
:::

如果想自定义入口点的异常处理,可以注册一个回调:

builder.RegisterEntryPointExceptionHandler(ex =>
{
    UnityEngine.Debug.LogException(ex);
    // 额外的处理 ...
});

如果有多个入口点,可以选择使用以下声明进行分组。

builder.UseEntryPoints(entryPoints =>
{
   entryPoints.Add<ScopedEntryPointA>();
   entryPoints.Add<ScopedEntryPointB>();
   entryPoints.Add<ScopedEntryPointC>().AsSelf();
   entryPoints.OnException(ex => ...)
});

这与以下代码相同:

builder.RegisterEntryPoint<ScopedEntryPointA>();
builder.RegisterEntryPoint<ScopedEntryPointB>();
builder.RegisterEntryPoint<ScopedEntryPointC>().AsSelf();
builder.RegisterEntryPointExceptionHandler(ex => ...);

更多信息参阅 纯 C# 入口点 部分。

注册现有实例

// ...
var obj = new ServiceA();
// ...

builder.RegisterInstance(obj);

:::note
RegisterIntance 总是具有 Singleton 生命周期,因此它不存在参数。
:::

可以这样解析:

class ClassA
{
    public ClassA(ServiceA serviceA) { /* ... */ }
}

:::note
容器不会管理 RegisterInstance 注册的实例的生命周期。

  • 不会自动执行 Dispose
  • 不会触发方法注入

如果希望容器管理创建的实例,请考虑使用以下替代方案:

将实例注册为接口

使用 As* 声明。

builder.RegisterInstance<IInputPort>(serviceA);

builder.RegisterInstance(serviceA)
    .As<IServiceA, IInputPort>();

builder.RegisterInstance(serviceA)
    .AsImplementedInterfaces();

参数化注册

如果类型不唯一,可以使用类型指定参数:

builder.Register<SomeService>(Lifetime.Singleton)
    .WithParameter<string>("http://example.com");

或使用键名来命名参数:

builder.Register<SomeService>(Lifetime.Singleton)
    .WithParameter("url", "http://example.com");

可以这样解析:

class SomeService
{
    public SomeService(string url) { /* ... */ }
}

此注册仅在注入到 SomeService 时有效。

class OtherClass
{
    // ! 错误
    public OtherClass(string hogehoge) { /* ... */ }
}

注册泛型类型

class GenericType<T>
{
    // ...
}
builder.Register(typeof(GenericType<>), Lifetime.Singleton);

可以这样解析:

class SomeService
{
    public SomeService(GenericType<int> closedGenericType) { /* ... */ }
}

在这种情况下,具体类型在运行时进行构造。Unity 2022.1+ 的 IL2CPP 已支持此动态类型定义,旧版本可能存在兼容性问题。

posted @   凌雪寒  阅读(8)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
· 三行代码完成国际化适配,妙~啊~
点击右上角即可分享
微信分享提示