VContainer-comparing/comparing-to-zenject | 对比 Zenject
import {Inline} from '../../src/components/CodeBlockInTable'
import {CodeSizeGraph} from "../../src/components/CodeSizeGraph"
VContainer 相比 Zenject 的优势:
- 性能更优。
- 反射操作集中在容器构建阶段。
- 代码更简洁。
- VContainer 的功能经过精心挑选,不会在容器中注册面向数据的对象,也不会主动注入 View 组件。防止 DI 声明变得过于复杂。
- Zenject 通常用于注入动态或以数据为中心的对象,但这很复杂。
- 在 VContainer 中,推荐使用 MonoBehaviour 注入而不是注入到 MonoBehaviour。
- Zenject 在场景启动时通过反射查找所有 GameObject,此操作会造成高昂开销;VContainer 则不会如此。
Code size (v1.3.0)
API 对照表
基础注册
| Zenject | VContainer |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
组件注册
| Zenject | VContainer |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Factory 工厂模式对比
使用参数 parameter
public class Enemy
{
readonly float speed;
public Enemy(float speed)
{
this.speed = speed;
}
public class Factory : PlaceholderFactory<float, Enemy>;
{
}
}
Container.BindFactory<float, Enemy, Enemy.Factory>();
public class Enemy
{
readonly float speed;
public Enemy(float speed)
{
this.speed = speed;
}
}
builder.RegisterFactory<float, Enemy>(speed => new Enemy(speed));
运行时使用参数并解析依赖关系
public class Enemy
{
readonly Player player;
readonly float speed;
public Enemy(float speed, Player player)
{
this.player = player;
this.speed = speed;
}
public class Factory : PlaceholderFactory<float, Enemy>;
{
}
}
Container.BindFactory<float, Enemy, Enemy.Factory>();
public class Enemy
{
readonly Player player;
readonly float speed;
public Enemy(float speed, Player player)
{
this.player = player;
this.speed = speed;
}
}
builder.RegisterFactory<float, Enemy>(container =>
{
var player = container.Resolve<Player>();
return speed => new Enemy(speed, player);
}, Lifetime.Scoped);
使用 prefab 预制体
public class Enemy : MonoBehaviour
{
Player player;
[Inject]
public void Construct(Player player)
{
this.player = player;
}
public class Factory : PlaceholderFactory<Enemy>
{
}
}
Container.BindFactory<Enemy, Enemy.Factory>()
.FromComponentInNewPrefab(enemyPrefab);
public class Enemy : MonoBehaviour
{
Player player;
public void Construct(Player player)
{
this.player = player;
}
}
builder.RegisterFactory<Enemy>(container =>
{
var player = container.Resolve<Player>();
return () =>
{
var enemy = Instantiate(enemyPrefab);
enemy.Construct(player);
return enemy;
};
}, Lifetime.Scoped);
其他差异
| Zenject | VContainer |
|---|---|
| Signal |
不支持
中央消息传递模式(central messaging pattern)很有用,但在很大程度上取决于项目的风格,首选的实现方式会有所不同。 可以选择任何其他实现,比如 VitalRouter、Cysharp/MessagePipe 等。 |
| Memory Pool(内存池) |
不支持
目前,没有嵌入任何内存池的实现。 请根据项目的需求,将实现注入到 Factory 等中。 |
|
|
不支持
应当使用 LoadAsync 系列方法来加载资源,并在加载资源后使用 RegisterInstance() 等方法进行注册。 |
|
|
不支持
不推荐重复类型的 Resolve。推荐使用特定类型的 Register,例如 builder.Register(Lifetime.Scoped).WithParameter("foo", foo)。 |

浙公网安备 33010602011771号