VContainer 初体验

news2024/10/5 18:32:29

IOC 控制反转

IOC 提供一个对象生成容器,在我们需要取得某个对象时,不再使用New关键字进行对象生成操作,而是通过IOC容器内部控制来获得对象。

使用这种思想方式,可以让我们无需关心对象的生成方式,只需要告诉容器我需要xxx对象即可,而高旭容器我需要xxx对象的方式就叫做DI依赖注入。

DI依赖注入

这种思想,我是在学习.net core时发现的,一般采用特性注入或者使用构造函数注入

经过标记的字段会在该类构造时在IOC容器中执行构造获取对应的对象示例。

VContainer

VContainer是在Unity端使用的一种轻量级的DI框架,通过GameLifeScope划分作用域,和普通的web后端的Di框架不同的是,针对Unity的Mono特殊性,提出了GameLifeScope的方式,通过在Game Object上挂载Scope,可以在代码中动态切换使用的实例和Scope。并且提供了一种父子继承Scope方式供用户使用。

Scope 作用域

作用域指函数、变量的作用范围,在Di中一般可以注册singleton单例,Trans复例等

在netcore中有类似下面这样的形式:

var serviceCollection = new ServiceCollection()
  .AddTransient<ILoginService, EFLoginService>()
  .AddSingleton<ILoginService, EFLoginService>()
  .AddScoped<ILoginService, EFLoginService>();

其中添加的Addxxxx就是为其添加一项注入并指定注入作用域,同时在这里进行的是一个接口的注入操作,在使用这个接口依赖时会生成一个对应的接口实现实例。

在VContainer中的注入和以上的方式很像。

单例?

一般来说,在Unity中我们会继承自一个泛型单例类。

  	/// <summary>
    /// 基础单例(线程锁)
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class Singleton<T> where T : new()
    {
        private static T _instance;

        public static T Instance
        {
            get
            {
                if (_instance != null) return _instance;
                try
                {
                    _instance = new T();
                    Debug.Log($"{typeof(T)}".Color(new Color(0.2f,0.6f,0.8f)) + "|单例OK");
                    Monitor.Enter(_instance);
                }
                finally
                {
                    Monitor.Exit(_instance);
                }

                return _instance;
            }
        }
    }

例如继承自这个泛型单例来实现单例效果,在Di中我们的实例无需在外部控制单例,直接由IOC容器管理。

GameLifeScope

为其GameObject添加一个继承自LifetimeScope的脚本即添加了一个Scope。

++ 游戏中至少需要有一个Scope ++

GameLifeScope

  public class BaseLifeScope : LifetimeScope
    {
        protected override void Configure(IContainerBuilder builder)
        {
            builder.Register<MusicManager>(Lifetime.Singleton);
            builder.RegisterInstance(GameSettingAssetMgr.Instance);
            builder.Register<UIManager>(Lifetime.Singleton);
            builder.RegisterEntryPoint<GameLauncher>();
            builder.RegisterEntryPoint<GameLoop>();
        }
    }

同时我们可以继承父级LifeScope来灵活选择我们的Scope实现。

  public class GameLiftScope : BaseLifeScope
    {
        public Character gamePanel;

        protected override void Configure(IContainerBuilder builder)
        {
            base.Configure(builder);


            builder.RegisterComponentInNewPrefab(gamePanel, Lifetime.Scoped);
        }
    }

可注入对象

在上面我们描述了Scope,使用 builder.Register<T>进行注册。

Mono

可注入Mono的对象,例如游戏中的UI等与Mono关系密切的对象。

可将场景中的GameObject直接注入到容器中来使用。

image-20221006113633790

Instance

可注入具体的对象实例,例如单例我们可以直接注入对象的单例,也可以在Scope中选择单例。

EnterPoint

EnterPoint可以说是VContainer设计十分精妙的部分——将Mono转移到普通的C#类中。

通过builder.RegisterEntryPoint<T>();注入一个入口点。这些入口点能够代替Unity的Start、Update、FixedUpdate等函数。

通过实现不同的> Ixxx接口重写方法来编写原生Unity事件,如下例子:


这是一个类似Start的实现,继承自IStartable即可,同时这里我注入了GameSettingAssetMgrMusicManager两个对象。

在游戏开始运行时,执行了打印当前游戏语言和播放Bgm的指令。

    public class GameLauncher : IStartable
    {
        [Inject] private readonly GameSettingAssetMgr _gameSettingAssetMgr;
        [Inject] private readonly MusicManager _musicManager;

        public GameLauncher(MusicManager musicManager, GameSettingAssetMgr gameSettingAssetMgr)
        {
            _musicManager = musicManager;
            _gameSettingAssetMgr = gameSettingAssetMgr;
        }

        public void Start()
        {
            Debug.Log(_gameSettingAssetMgr.lan);
            _musicManager.PlayBgm("12345SEX");
        }
    }

可以看到,在我运行游戏时,根据依赖自动生成了对象并执行了相关操作。

image-20221006112341489

同理我们可以,实现更多的接口来实现更多的Unity原生事件,将原本Mono脚本才能执行的内容转移到普通Class中。

现在让我们为GameLauncher类实现Update实现。

实现ITickable接口
    
public void Tick()
{
    if (Input.GetKeyDown(KeyCode.Q))
    {
        _uiManager.ShowPanel("GamePanel", UILayer.Mid);
        Debug.Log("显示面板");
    }

    if (Input.GetKeyDown(KeyCode.W))
    {
        _uiManager.SwitchShowState("GamePanel");
        Debug.Log("切换面板显示");
    }
}

在Mono中使用

因为Mono不支持构造函数,所以在Mono中使用时必须使用注入特性或注入方法的方式。

builder.RegisterComponentInHierarchy<Character>();

注入特性

        [Inject] private MusicManager _musicManager;
        [Inject] private GameSettingAssetMgr _gameSettingAssetMgr;

注入方法

        private MusicManager _musicManager;
        private GameSettingAssetMgr _gameSettingAssetMgr;


        [Inject]
        public void Inject(GameSettingAssetMgr gameSettingAssetMgr, MusicManager musicManager)
        {
            _gameSettingAssetMgr = gameSettingAssetMgr;
            _musicManager = musicManager;
        }

相关链接

  1. 关于|虚拟容器 (hadashikick.jp)
  2. hadashiA/VContainer: The extra fast, minimum code size, GC-free DI (Dependency Injection) library running on Unity Game Engine. (github.com)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/416566.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

xmanager连接linux桌面教程 xmanager连接之后黑屏

xmanager 是一款专业的远程服务器管理软件&#xff0c;但习惯了使用Windows系统下的桌面&#xff0c;一时会无法适应linux服务器的命令行界面。下面我就为大家介绍xmanager连接linux桌面教程&#xff0c;xmanager连接之后黑屏的相关内容&#xff0c;让大家在使用linux更加方便。…

node.js详解

文章目录1.Node.js1.1 Node.js 模块化1.2 模块暴露数据1.2.1 模块初体验1.2.2 暴露数据1.3.导入(引入)模块1.4 JavaScript引擎1.5 什么是Node.js1.6 BFF2.包管理工具2.1 npm2.1.1 npm 的安装2.1.2 npm 基本使用2.1.2.1 初始化2.1.2.2 搜索包2.1.2.2 下载安装包2.1.2.3 require …

java遍历字符串的方法

在 java中&#xff0c;我们需要遍历字符串&#xff0c;如何遍历呢&#xff1f;首先我们先了解一下遍历的概念&#xff1a; 在我们的计算机中&#xff0c;存储的都是二进制数据&#xff0c;为了方便存储和管理&#xff0c;我们把一段数据分成多个字符串。在 java中&#xff0c;遍…

BM36-判断是不是平衡二叉树

题目 输入一棵节点数为 n 二叉树&#xff0c;判断该二叉树是否是平衡二叉树。 在这里&#xff0c;我们只需要考虑其平衡性&#xff0c;不需要考虑其是不是排序二叉树 平衡二叉树&#xff08;Balanced Binary Tree&#xff09;&#xff0c;具有以下性质&#xff1a;它是一棵空…

LabVIEW-簇数据类型

簇数据类似于 C 语言的结构体&#xff0c;创建时&#xff0c;首先将“簇”放置到前面板上&#xff1a; 然后放置簇内的元素&#xff0c;比如“数值输入控件”&#xff0c;当“簇框架”内边沿出现虚线框时&#xff0c;单击“数值输入控件”即可添加到簇中:在簇中也可以修改“数值…

常见网络协议汇总(一)

“网络协议”是指为完成特定的任务而制定的一套规则。网络协议通常用来表示数据传输中一组用于实现一个或多个OT模型级别的规则或规范。在通信时&#xff0c;网络协议定义了在通信时如何进行通信。今天海翎光电的小编就汇总了常见的网络协议&#xff0c;来一起看看。我们先回顾…

Linux基础IO(下)

Linux基础IO&#xff08;下&#xff09;FILE自己模拟实现fopen/fclose、fread/fwrite理解文件系统OS如何看待磁盘管理磁盘硬链接软连接ACM时间动态库和静态库见一见Linux下的库为什么要有库写一写库制作一个静态库制作一个动态库关于动静态库的一点小实验FILE 通过前面学习我们…

【SSM】Spring6(十二.Spring6集成MyBatis3.5)

文章目录1. 实现步骤2.具体实现2.1 准备数据库2.2 创建模块&#xff0c;引入依赖2.3 创建包2.4 创建Pojo类2.5 编写mapper接口2.6 编写Mapper配置文件2.7 编写service接口和service接口实现类2.8 编写jdbc.properties配置文件2.9 编写mybatis-config.xml配置文件2.10编写spring…

什么是数字“指纹”?

今天的网站收集有关访问者的大量信息&#xff0c;不仅用于广告、业务优化和用户体验&#xff0c;还用于安全目的。 除了 cookie 之外&#xff0c;网站还使用“指纹识别”来收集有关用户网络浏览器、硬件、设备配置、时区甚至行为模式的信息&#xff0c;以授权合法用户或取消对…

考虑可再生能源消纳的电热综合能源系统日前经济调度模型

目录 1 主要内容 模型示意图 目标函数 程序亮点 2 部分程序 3 程序结果 4 程序链接 1 主要内容 本程序参考文献《考虑可再生能源消纳的建筑综合能源系统日前经济调度模型》模型&#xff0c;建立了电热综合能源系统优化调度模型&#xff0c;包括燃气轮机、燃气锅炉、余热…

飞腾D2000 UOS下安装KVM虚拟机

其他的和x86环境都差不多&#xff0c;开了开发者模式后&#xff0c;virt-manager qemu-efi-aarch64 qemu-system 几个包补齐&#xff0c;启动libvirtd服务&#xff0c;查看日志&#xff0c;报以下日志&#xff0c; 4月 09 21:13:34 actionchen-PC systemd[1]: Starting Virtu…

SQL select总结(基于选课系统)

表详情&#xff1a; 学生表&#xff1a; 学院表&#xff1a; 学生选课记录表&#xff1a; 课程表&#xff1a; 教师表&#xff1a; 查询&#xff1a; 1. 查全表 -- 01. 查询所有学生的所有信息 -- 方法一&#xff1a;会更复杂&#xff0c;进行了两次查询&#xff0c;第一…

C语言实现扫雷教学

本篇博客会讲解&#xff0c;如何使用C语言实现扫雷小游戏。 0.思路及准备工作 使用2个二维数组mine和show&#xff0c;分别来存储雷的位置信息和排查出来的雷的信息&#xff0c;前者隐藏&#xff0c;后者展示给玩家。假设盘面大小是99&#xff0c;这2个二维数组都要开大一圈…

JavaDS——数据结构易错选择题总结

1. 下列关于线性链表的叙述中&#xff0c;正确的是&#xff08; &#xff09; A. 各数据结点的存储空间可以不连续&#xff0c;但它们的存储顺序与逻辑顺序必须一致 B. 各数据结点的存储顺序与逻辑顺序可以不一致&#xff0c;但它们的存储空间必须连续 C. 进行插入与删除时&am…

【数据结构】-快速排序的四种方法实现以及优化

作者&#xff1a;小树苗渴望变成参天大树 作者宣言&#xff1a;认真写好每一篇博客 作者gitee:gitee 如 果 你 喜 欢 作 者 的 文 章 &#xff0c;就 给 作 者 点 点 关 注 吧&#xff01; 快速排序前言一、hoare法&#xff08;左右指针法&#xff09;二、挖坑法三、前后指针法…

Midjourney AI绘画工具使用保姆级教程

系列文章目录 之后补充 文章目录系列文章目录写在前面一、Midjourney是什么&#xff1f;二、使用步骤1.完成Discord注册2.打开Midjourney官网3.开始画图后记写在前面 据悉&#xff0c;自3月30日&#xff0c;Midjourney已叫停免费试用服务&#xff0c;如上图所示。 创始人表示原…

代码随想录_226翻转二叉树、101对称二叉树

leetcode 226. 翻转二叉树 ​​​226. 翻转二叉树 给你一棵二叉树的根节点 root &#xff0c;翻转这棵二叉树&#xff0c;并返回其根节点。 示例 1&#xff1a; 输入&#xff1a;root [4,2,7,1,3,6,9] 输出&#xff1a;[4,7,2,9,6,3,1]示例 2&#xff1a; 输入&#xff1a;r…

【Android开发】App Bundle技术之动态功能模块

前言 自 2021 年 8 月起&#xff0c;Google Play 将开始要求新应用使用 Android App Bundle 进行发布。该格式将取代 APK 作为标准发布格式。虽然这个政策目前还无法影响到国内应用&#xff0c;但是作为Android开发者&#xff0c;对于新的动态还是要有一定的认识。 Android A…

产品经理必读|用户研究方法总结②

随着互联网的发展&#xff0c;用户体验设计逐渐成为了产品设计中不可或缺的一部分&#xff0c;而要进行好的用户体验设计&#xff0c;就需要进行用研。但是&#xff0c;如何选用合适的用研方法&#xff0c;却是很多产品经理和设计师面临的难题。下面&#xff0c;就让我们来探讨…

3.3 泰勒公式

学习目标&#xff1a; 复习微积分基础知识。泰勒公式是微积分的一个重要应用&#xff0c;因此在学习泰勒公式之前&#xff0c;需要复习微积分的基本概念和技能&#xff0c;包括函数的导数和微分、极限、定积分等。可以参考MIT的微积分课程进行复习和加强。 学习泰勒级数和泰勒…