引入redis服务,支持自动化单元测试
大石头 编写于 2022-03-31 22:56:30
X
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;

namespace NewLife.Model
{
    /// <summary>轻量级对象容器,支持注入</summary>
    /// <remarks>
    /// 文档 https://www.yuque.com/smartstone/nx/object_container
    /// </remarks>
    public class ObjectContainer : IObjectContainer
    {
        #region 静态
        /// <summary>当前容器</summary>
        public static IObjectContainer Current { get; set; } = new ObjectContainer();

        /// <summary>当前容器提供者</summary>
        public static IServiceProvider Provider { get; set; } = new ServiceProvider(Current);
        #endregion

        #region 属性
        private readonly IList<IObject> _list = new List<IObject>();

        /// <summary>注册项个数</summary>
        public Int32 Count => _list.Count;
        #endregion

        #region 方法
        /// <summary>添加</summary>
        /// <param name="item"></param>
        public void Add(IObject item)
        {
            lock (_list)
            {
                for (var i = 0; i < _list.Count; i++)
                {
                    // 覆盖重复项
                    if (_list[i].ServiceType == item.ServiceType)
                    {
                        _list[i] = item;
                        return;
                    }
                }

                _list.Add(item);
            }
        }

        /// <summary>添加</summary>
        /// <param name="item"></param>
        public Boolean TryAdd(IObject item)
        {
            if (_list.Any(e => e.ServiceType == item.ServiceType)) return false;
            lock (_list)
            {
                if (_list.Any(e => e.ServiceType == item.ServiceType)) return false;

                _list.Add(item);

                return true;
            }
        }
        #endregion

        #region 注册
        /// <summary>注册</summary>
        /// <param name="serviceType">接口类型</param>
        /// <param name="implementationType">实现类型</param>
        /// <param name="instance">实例</param>
        /// <returns></returns>
        [EditorBrowsable(EditorBrowsableState.Never)]
        public virtual IObjectContainer Register(Type serviceType, Type implementationType, Object instance)
        {
            if (serviceType == null) throw new ArgumentNullException(nameof(serviceType));

            var item = new ObjectMap
            {
                ServiceType = serviceType,
                ImplementationType = implementationType,
                Instance = instance,
                Lifttime = instance == null ? ObjectLifetime.Transient : ObjectLifetime.Singleton,
            };
            Add(item);

            return this;
        }
        #endregion

        #region 解析
        /// <summary>解析类型的实例</summary>
        /// <param name="serviceType">接口类型</param>
        /// <returns></returns>
        [EditorBrowsable(EditorBrowsableState.Never)]
        public virtual Object Resolve(Type serviceType)
        {
            if (serviceType == null) throw new ArgumentNullException(nameof(serviceType));

            var item = _list.FirstOrDefault(e => e.ServiceType == serviceType);
            //var item = _list.LastOrDefault(e => e.ServiceType == serviceType);
            if (item == null) return null;

            var map = item as ObjectMap;
            var type = item.ImplementationType ?? item.ServiceType;
            switch (item.Lifttime)
            {
                case ObjectLifetime.Singleton:
                    if (map != null)
                    {
                        if (map.Instance == null) map.Instance = CreateInstance(type, new ServiceProvider(this), map.Factory);

                        return map.Instance;
                    }
                    return CreateInstance(type, new ServiceProvider(this), null);

                //case ObjectLifetime.Scoped:
                case ObjectLifetime.Transient:
                default:
                    return CreateInstance(type, new ServiceProvider(this), map?.Factory);
            }
        }

        private static IDictionary<TypeCode, Object> _defs;
        private Object CreateInstance(Type type, IServiceProvider provider, Func<IServiceProvider, Object> factory)
        {
            if (factory != null) return factory(provider);

            // 初始化
            if (_defs == null)
            {
                var dic = new Dictionary<TypeCode, Object>
                {
                    { TypeCode.Empty, null },
                    { TypeCode.DBNull, null},
                    { TypeCode.Boolean, false },
                    { TypeCode.Char, (Char)0 },
                    { TypeCode.SByte, (SByte)0 },
                    { TypeCode.Byte, (Byte)0 },
                    { TypeCode.Int16, (Int16)0 },
                    { TypeCode.UInt16, (UInt16)0 },
                    { TypeCode.Int32, (Int32)0 },
                    { TypeCode.UInt32, (UInt32)0 },
                    { TypeCode.Int64, (Int64)0 },
                    { TypeCode.UInt64, (UInt64)0 },
                    { TypeCode.Single, (Single)0 },
                    { TypeCode.Double, (Double)0 },
                    { TypeCode.Decimal, (Decimal)0 },
                    { TypeCode.DateTime, DateTime.MinValue },
                    { TypeCode.String, null }
                };

                _defs = dic;
            }

            ParameterInfo errorParameter = null;
            if (!type.IsAbstract)
            {
                // 选择构造函数,优先选择参数最多的可匹配构造函数
                var constructors = type.GetConstructors();
                foreach (var constructorInfo in constructors.OrderByDescending(e => e.GetParameters().Length))
                {
                    if (constructorInfo.IsStatic) continue;

                    ParameterInfo errorParameter2 = null;
                    var ps = constructorInfo.GetParameters();
                    var pv = new Object[ps.Length];
                    for (var i = 0; i != ps.Length; i++)
                    {
                        if (pv[i] != null) continue;

                        var ptype = ps[i].ParameterType;
                        if (_defs.TryGetValue(Type.GetTypeCode(ptype), out var obj))
                            pv[i] = obj;
                        else
                        {
                            var service = provider.GetService(ps[i].ParameterType);
                            if (service == null)
                            {
                                errorParameter2 = ps[i];

                                break;
                            }
                            else
                            {
                                pv[i] = service;
                            }
                        }
                    }

                    if (errorParameter2 == null) return constructorInfo.Invoke(pv);
                    errorParameter = errorParameter2;
                }
            }
            throw new InvalidOperationException($"未找到适合 '{type}' 的构造函数,请确认该类型构造函数所需参数均已注册。无法解析参数 '{errorParameter}'");
        }
        #endregion

        #region 辅助
        /// <summary>已重载。</summary>
        /// <returns></returns>
        public override String ToString() => $"{GetType().Name}[Count={Count}]";
        #endregion
    }

    /// <summary>对象映射</summary>
    internal class ObjectMap : IObject
    {
        #region 属性
        /// <summary>服务类型</summary>
        public Type ServiceType { get; set; }

        /// <summary>实现类型</summary>
        public Type ImplementationType { get; set; }

        /// <summary>生命周期</summary>
        public ObjectLifetime Lifttime { get; set; }

        /// <summary>实例</summary>
        public Object Instance { get; set; }

        /// <summary>对象工厂</summary>
        public Func<IServiceProvider, Object> Factory { get; set; }
        #endregion

        #region 方法
        /// <summary>显示友好名称</summary>
        /// <returns></returns>
        public override String ToString() => $"[{ServiceType?.Name},{ImplementationType?.Name}]";
        #endregion
    }

    internal class ServiceProvider : IServiceProvider
    {
        private readonly IObjectContainer _container;
        /// <summary>容器</summary>
        public IObjectContainer Container => _container;

        public ServiceProvider(IObjectContainer container) => _container = container;

        public Object GetService(Type serviceType)
        {
            if (serviceType == typeof(IObjectContainer)) return _container;
            if (serviceType == typeof(IServiceProvider)) return this;

            return _container.Resolve(serviceType);
        }
    }
}