IOC的优化

上篇文章讲到了基础的Ioc这篇文章我们将对其进行拓展方便我们框架的后期使用

框架:GitHub - DSHGFHDS/Cirilla: 适配HuaTuo、轻量、友好、易维护、可热更的Unity3d客户端框架x

感兴趣的小伙伴的可拉取一下。

下面开始对Ioc的拓展(老规矩本章不对Ioc进行抽象如果有小伙感兴趣可以自己尝试,丰富自己的动手能力)

//类型为 class ;接口为interface;实例为new过之后的类型
public class IocContainer 
    {
        //单例,创建的方法大家不要模仿
        public static IocContainer _ins=this;
        //这个到我们用到在进行解释
          private const BindingFlags Flag = BindingFlags.NonPublic | BindingFlags.Instance                 
                                            | BindingFlags.DeclaredOnly;
        //进行了拓展,Type为父接口让我们的注册更加明了
        //上篇注册主要进行注册他就存在当我们类型多了就会产生些许影响
        //该篇对类型进行了分类,使我们寻找容器简单了许多(只需在自己的Type字典中)
        private Dictionary<Type, Dictionary<string, ContentInfo>> stock;    
//构造
 public IocContainer() => stock = new Dictionary<Type, Dictionary<string, ContentInfo>>();

  /// <summary>
  /// 注册方法
  /// </summary>
  /// <typeparam name="T">父接口</typeparam>
  /// <param name="type">注入的类型</param>
  /// <param name="key">该类型的名称</param>
public void Register<T>(Type type, string key) =>
     Register<T>(key, new ContentInfo(type, key, null));


  /// <summary>
  ///对该类型进行注入
  /// </summary>
  /// <typeparam name="T">Type需要注册的类型</typeparam>
  /// <param name="key"></param>
  /// <param name="contentInfo"></param>
  private void Register<T>(string key, ContentInfo contentInfo)
  {
            Type type = typeof(T);
            if (stock.TryGetValue(type, 
                out Dictionary<string, ContentInfo> contentInfos))
            {
                //判断容器是否存在同一个类型
                if (contentInfos.ContainsKey(key))
                    return;

                contentInfos.Add(key, contentInfo);

                return;
            }
            //对容器进行存储
            stock.Add(type, 
            new Dictionary<string, ContentInfo>() { { key, contentInfo } });
        }
    }

    /// <summary>
    /// 既然把类型注入到容器中则需要使用,该Api为获取实例
    /// </summary>
    /// <typeparam name="T">Type(需要获取实例的父接口)</typeparam>
    /// <param name="key">该类型注册时的名称</param>
    /// <returns></returns>
    public object Resolve(Type type, string key)
        {
            if (!stock.TryGetValue(type, 
            out Dictionary<string, ContentInfo> contentInfos))
            {
                Debug.Log("类型未注册:" + type);
                return null;
            }

            if (!contentInfos.TryGetValue(key, out ContentInfo contentInfo))
            {
                Debug.Log("键值未注册:" + key);
                return null;
            }

            object obj = contentInfo.obj;
            if (contentInfo.IsInjected)
                return obj;
            //对该类型的标记字段进行实例化
            Inject(contentInfo);
            contentInfo.IsInjected = true;

            return obj;
        }

         /// <summary>
        /// 对Type的字段(被特性标记过的字段)进行实例获取
        /// </summary>
        /// <param name="contentInfo"></param>
        private void Inject(ContentInfo contentInfo)
        {
            //先获取实例
            Object obj = contentInfo.obj;
            //需要用到反射所以获取类型
            Type type = obj.GetType();
            //获取type中的字段属性()
            //通过反射获取全部到字段Flag被使用
            FieldInfo[] fieldInfo = type.GetFields(Flag);
            for (int i = 0; i < fieldInfo.Length; i++)
            {
                 //对字段进行保存
                contentInfo.fieldInfos.Add(fieldInfo[i]);
                //通过获取标记若该字段被标记则进行下一步,反之下一关循环
                DependencyAttribute attribute =                     
                fieldInfo[i].GetCustomAttribute<DependencyAttribute>();
                if (attribute == null)
                    continue;
                //获取该字段的类型
                Type fieldType = fieldInfo[i].FieldType;
                //调用获取实例的方法
                object target = Resolve(fieldType, attribute.key);
                //需要该类型被注册到容器才获取得到
                if(target == null)
                {
                    debug.Log("未注册:" + type.Name);
                    continue;
                }
            //对该实例的字段进行赋值
                fieldInfo[i].SetValue(obj, target);
            }
        }

下面是容器ContentInfo的拓展

public class ContentInfo
    {
        //注册的类型
        public Type type { get; private set; }
        //注册的名字
        public string key { get; private set; }
        //该类型的标记字段
        public List<FieldInfo> fieldInfos; 
        //该容器是否已经经过IocContainer.Inject
        public bool IsInjected { get; set; }
        //创建实例
        public object obj { get { return ins ?? (ins = Activator.CreateInstance(type)); } }
        private object ins { get; set; }
        //构造
        public ContentInfo(Type type, string key)
        {
            this.type = type;
            this.key = key;
            this.ins = ins;
        }
    }

下面是标签(特性)

   [AttributeUsage(AttributeTargets.Field, AllowMultiple = false, Inherited = true)]
    public class DependencyAttribute : Attribute
    {
        public string key { get; private set; }
        public DependencyAttribute(string key = ""){
            this.key = key;
        }
    }

使用:

 private void Start()
        {
            IocContainer  container=IocContainer._ins;
            //这样就注册进去了一个Type,
            container.Register<父接口, 子类型>(子类型.tostring());
            container.Register<功能父接口, 功能类型>(功能类型.tostring());
            //当子类型被获取实例后功能类自动被获取实例
           子类型 xxx=container.Resolve(接口,子类型.tostring());
        }
class 子类型:父接口
{
[Dependency("功能类型")] 功能类 xxx;
}

其实对Ioc还可以继续拓展还就是获取当容器,以及移除容器;这些由各位小伙伴自行拓展。

如有问题,或是更好的想法欢迎留言!!!!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值