导读:本期聚焦于小伙伴创作的《C# 如何实现一个简单的依赖注入容器 - 反射与字典的应用》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《C# 如何实现一个简单的依赖注入容器 - 反射与字典的应用》有用,将其分享出去将是对创作者最好的鼓励。

依赖注入是C#项目中降低组件耦合度的常用设计模式,其核心思想是对象的依赖由外部容器提供,而非自身创建。要实现一个简单的依赖注入容器,核心逻辑可以拆分为服务注册和服务解析两部分,而反射和字典正是实现这两个功能的关键工具。

C# 如何实现一个简单的依赖注入容器 - 反射与字典的应用

核心设计思路

依赖注入容器的基本工作流程是:先通过字典存储服务类型到实现类型的映射关系,也就是服务注册;当需要获取服务实例时,通过反射根据映射关系动态创建实现类型的对象,也就是服务解析。整个流程不需要手动new对象,完全由容器托管。

服务注册逻辑

服务注册的本质是把服务接口(或基类)和对应的实现类建立映射,存储到字典中。我们定义一个字典,键是服务类型,值是服务的生命周期和对应的实现类型,这里先实现最简单的瞬态生命周期,每次解析都创建新实例。

using System;
using System.Collections.Generic;

namespace SimpleDIContainer
{
    // 容器类
    public class DIContainer
    {
        // 存储服务类型到实现类型的映射字典
        private readonly Dictionary<Type, Type> _serviceMappings = new Dictionary<Type, Type>();

        /// <summary>
        /// 注册服务,键为服务类型,值为实现类型
        /// </summary>
        /// <typeparam name="TService">服务类型(接口或基类)</typeparam>
        /// <typeparam name="TImplementation">实现类型</typeparam>
        public void Register<TService, TImplementation>() where TImplementation : TService
        {
            var serviceType = typeof(TService);
            var implementationType = typeof(TImplementation);
            // 检查是否已经注册过该服务
            if (_serviceMappings.ContainsKey(serviceType))
            {
                throw new InvalidOperationException($"服务 {serviceType.Name} 已经被注册过了");
            }
            _serviceMappings.Add(serviceType, implementationType);
        }
    }
}

服务解析逻辑

服务解析时,首先从字典中获取服务对应的实现类型,然后通过反射创建该类型的实例。如果实现类型有构造函数,反射会自动匹配最合适的构造函数,这里我们先处理无参构造函数的情况,后续可以扩展带参构造函数的解析。

using System;
using System.Collections.Generic;
using System.Reflection;

namespace SimpleDIContainer
{
    public class DIContainer
    {
        private readonly Dictionary<Type, Type> _serviceMappings = new Dictionary<Type, Type>();

        public void Register<TService, TImplementation>() where TImplementation : TService
        {
            var serviceType = typeof(TService);
            var implementationType = typeof(TImplementation);
            if (_serviceMappings.ContainsKey(serviceType))
            {
                throw new InvalidOperationException($"服务 {serviceType.Name} 已经被注册过了");
            }
            _serviceMappings.Add(serviceType, implementationType);
        }

        /// <summary>
        /// 解析服务实例
        /// </summary>
        /// <typeparam name="TService">要解析的服务类型</typeparam>
        /// <returns>服务实例</returns>
        public TService Resolve<TService>()
        {
            return (TService)Resolve(typeof(TService));
        }

        /// <summary>
        /// 内部解析方法,处理Type类型参数
        /// </summary>
        private object Resolve(Type serviceType)
        {
            // 检查服务是否已经注册
            if (!_serviceMappings.TryGetValue(serviceType, out var implementationType))
            {
                throw new InvalidOperationException($"服务 {serviceType.Name} 未被注册");
            }

            // 获取实现类型的无参构造函数
            var constructor = implementationType.GetConstructor(Type.EmptyTypes);
            if (constructor == null)
            {
                throw new InvalidOperationException($"实现类型 {implementationType.Name} 没有无参构造函数");
            }

            // 通过反射调用构造函数创建实例
            return constructor.Invoke(null);
        }
    }
}

实际使用示例

我们可以定义简单的服务接口和实现类,测试容器的功能是否正常。首先定义两个服务,一个是日志接口和实现,一个是用户服务,用户服务依赖日志服务。

using System;

namespace SimpleDIContainer
{
    // 日志服务接口
    public interface ILogService
    {
        void Log(string message);
    }

    // 日志服务实现
    public class ConsoleLogService : ILogService
    {
        public void Log(string message)
        {
            Console.WriteLine($"日志内容:{message}");
        }
    }

    // 用户服务接口
    public interface IUserService
    {
        void AddUser(string userName);
    }

    // 用户服务实现,依赖ILogService
    public class UserService : IUserService
    {
        private readonly ILogService _logService;

        // 带参构造函数,后续可以扩展容器支持解析构造函数参数
        public UserService(ILogService logService)
        {
            _logService = logService;
        }

        public void AddUser(string userName)
        {
            _logService.Log($"新增用户:{userName}");
        }
    }
}

然后编写测试代码,注册服务并解析使用:

using System;

namespace SimpleDIContainer
{
    class Program
    {
        static void Main(string[] args)
        {
            var container = new DIContainer();
            // 注册服务
            container.Register<ILogService, ConsoleLogService>();
            // 这里暂时只测试无参构造函数的服务,带参的需要扩展容器逻辑
            // container.Register<IUserService, UserService>();

            // 解析服务
            var logService = container.Resolve<ILogService>();
            logService.Log("依赖注入容器测试成功");
        }
    }
}

功能扩展方向

当前实现的容器只支持无参构造函数的瞬态服务,实际使用中还可以做很多扩展:比如支持带参构造函数的解析,自动递归解析构造函数的参数依赖;增加单例生命周期,同一个服务多次解析返回同一个实例;支持开放泛型注册,比如IRepository<T>映射到Repository<T>等。反射和字典的核心逻辑不变,只需要在现有基础上补充对应的判断和处理逻辑即可。

注意事项

  • 反射创建对象的性能比直接new要低,如果对性能要求高的场景,可以加入表达式树缓存构造函数委托,减少反射调用次数。
  • 注册服务时要确保实现类型可以转换为服务类型,泛型约束已经做了基础校验,非泛型注册时也需要做类型兼容性判断。
  • 循环依赖的问题需要处理,比如服务A依赖服务B,服务B又依赖服务A,解析时会无限递归,需要增加循环依赖检测逻辑。

C#依赖注入反射DictionaryIOC修改时间:2026-07-02 05:24:42

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。