当前位置: 首页 > news >正文

手撕代码:C#.NET实现自定义IOC容器

一、概要

        手撕IOC容器的代码实现,下面是一个基于C#实现的功能强大的IOC容器示例。这个容器将包括服务的注册与注入、单例模式、工厂方法、构造函数注入、属性注入、方法注入、自动装配、生命周期管理和注解支持等功能。

二、实现

1、基础设施

        首先需要定义一些基础设施,包括服务生命周期枚举、服务描述类等。

public class IocContainerClass
{public enum MyIocServiceLifetime{Singleton,Transient,Scoped}public class MyIocServiceDescriptor{public Type ServiceType { get; }public Type ImplementationType { get; }public object? ImplementationInstance { get; set; }public MyIocServiceLifetime Lifetime { get; }public MyIocServiceDescriptor(Type serviceType, Type implementationType, MyIocServiceLifetime lifetime) { ServiceType = serviceType;ImplementationType = implementationType;Lifetime = lifetime;}}
}
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Method)]
public class MyIocInjectAttribute : Attribute
{
}

        Singleton:单例生命周期

        Transient:瞬时生命周期

        Scoped:作用域生命周期

2、服务注册

        接下来需要一个容器来管理服务的注册和解析。

 public class MyIocServiceCollection{private readonly List<MyIocServiceDescriptor> _services = new List<MyIocServiceDescriptor>();public void AddSingleton<TService,TImplementation>() where TService: class where TImplementation :class, TService{_services.Add(new MyIocServiceDescriptor(typeof(TService),typeof(TImplementation), MyIocServiceLifetime.Singleton));}public void AddTransient<TService,TImplementation>() where TService : class where TImplementation : class, TService{_services.Add(new MyIocServiceDescriptor(typeof(TService),typeof(TImplementation), MyIocServiceLifetime.Transient));}public void AddScoped<TService,TImplementation>() where TService : class where TImplementation : class, TService{_services.Add(new MyIocServiceDescriptor(typeof(TService), typeof(TImplementation), MyIocServiceLifetime.Scoped));}public MyServiceProvider BuildServiceProvider(){return new MyServiceProvider(_services);}}
3、服务获取解析

        这里需要定义一个服务提供者,用于解析已注册的服务返回等。

public class MyServiceProvider : IDisposable
{private readonly Dictionary<Type, MyIocServiceDescriptor> _serviceDescriptor;private readonly Dictionary<Type, object?> _scopedInstances = new Dictionary<Type, object?>();private readonly bool _isRootProvider;public MyServiceProvider(List<MyIocServiceDescriptor> descriptors) {_serviceDescriptor = descriptors.ToDictionary(s => s.ServiceType, s => s);_isRootProvider = true;}private MyServiceProvider(Dictionary<Type, MyIocServiceDescriptor> serviceDescriptors){_serviceDescriptor = serviceDescriptors;_isRootProvider = false;}public MyServiceProvider CreateScope(){return new MyServiceProvider(_serviceDescriptor);}public object? GetService(Type serviceType){if(_serviceDescriptor.TryGetValue(serviceType, out var serviceDescriptor)){//单例生命周期if(serviceDescriptor.Lifetime == MyIocServiceLifetime.Singleton) { if(serviceDescriptor.ImplementationInstance == null){serviceDescriptor.ImplementationInstance = CreateInstance(serviceDescriptor.ImplementationType);}return serviceDescriptor.ImplementationInstance;}//作用域生命周期if(serviceDescriptor.Lifetime == MyIocServiceLifetime.Scoped){if (!_scopedInstances.ContainsKey(serviceType)){_scopedInstances[serviceType] = CreateInstance(serviceDescriptor.ImplementationType);}return _scopedInstances[serviceType];}//瞬时生命周期return CreateInstance(serviceDescriptor.ImplementationType);}else{throw new Exception($"Service of type {serviceType.Name} is not registered.");}}public T? GetService<T>(){return (T?)GetService(typeof(T?));}public void Dispose(){if (!_isRootProvider){foreach (var scopedInstance in _scopedInstances.Values){if (scopedInstance is IDisposable disposable){disposable.Dispose();}}}}
4、依赖注入

        使用反射创建实例,实现构造函数注入、方法注入和属性注入等。

public object? CreateInstance(Type type)
{#region 构造函数注入// 获取所有公共构造函数var constructors = type.GetConstructors();// 按参数数量降序排列,选择参数最多的构造函数var constructor = constructors.OrderByDescending(c => c.GetParameters().Length).First();// 获取构造函数的参数var parameters = constructor.GetParameters().Select(p => GetService(p.ParameterType)).ToArray();var instance = Activator.CreateInstance(type, parameters);#endregion//属性注入foreach (var property in type.GetProperties().Where(s => s.CanWrite &&s.GetCustomAttributes(typeof(MyIocInjectAttribute), true).Any())){if (_serviceDescriptor.ContainsKey(property.PropertyType)){property.SetValue(instance, GetService(property.PropertyType));}}//方法注入foreach (var method in type.GetMethods().Where(m=>m.IsPublic && m.ReturnType == typeof(void) &&m.GetCustomAttributes(typeof(MyIocInjectAttribute), true).Any())){var methodparams = method.GetParameters().Select(p => GetService(p.ParameterType)).ToArray();method.Invoke(instance, methodparams);}return instance;
}

三、测试验证

1、测试服务实例
 public interface IFooService{void DoSomething();}public class FooService : IFooService
{private static int _instanceCount = 0;public int InstanceId { get; }public FooService(){InstanceId = ++_instanceCount;}public void DoSomething(){Console.WriteLine($"FooService instance {InstanceId} doing something...");}
}
2、需要依赖注入的实例
public class ConstructorInject_BarService
{private readonly IFooService _fooService;        //构造函数注入public ConstructorInject_BarService(IFooService fooService){_fooService = fooService;}        public void Execute(){_fooService.DoSomething();}
}
public class PropertyInject_BarService
{//属性注入[MyIocInject]public IFooService? FooService { get; set; }             public void Execute(){FooService?.DoSomething();}
}
public class MethodInject_BarService
{private IFooService? _fooService;//方法注入[MyIocInject]public void Initialize(IFooService fooService){_fooService = fooService;}public void Execute(){_fooService?.DoSomething();}
}
3、使用示例代码
class Program
{static void Main(string[] args){var services = new ServiceCollection();services.AddSingleton<IFooService, FooService>();services.AddTransient<BarService, BarService>();services.AddScoped<IFooService, FooService>();var serviceProvider = services.BuildServiceProvider();Console.WriteLine("Resolving BarService for the first time:");using (var scope1 = serviceProvider.CreateScope()){var barService1 = scope1.GetService<BarService>();barService1.Execute();var scopedFooService1 = scope1.GetService<IFooService>();scopedFooService1.DoSomething();var scopedFooService2 = scope1.GetService<IFooService>();scopedFooService2.DoSomething();Console.WriteLine($"Scoped instances are same: {object.ReferenceEquals(scopedFooService1, scopedFooService2)}");}Console.WriteLine("\nResolving BarService for the second time:");using (var scope2 = serviceProvider.CreateScope()){var barService2 = scope2.GetService<BarService>();barService2.Execute();var scopedFooService3 = scope2.GetService<IFooService>();scopedFooService3.DoSomething();var scopedFooService4 = scope2.GetService<IFooService>();scopedFooService4.DoSomething();Console.WriteLine($"Scoped instances are same: {object.ReferenceEquals(scopedFooService3, scopedFooService4)}");}Console.WriteLine("\nResolving IFooService directly:");var fooService1 = serviceProvider.GetService<IFooService>();fooService1.DoSomething();var fooService2 = serviceProvider.GetService<IFooService>();fooService2.DoSomething();Console.WriteLine($"Singleton instances are same: {object.ReferenceEquals(fooService1, fooService2)}");}
}
4、运行结果

        运行上述代码,您应该会看到类似以下的输出:

Resolving BarService for the first time:
FooService instance 1 doing something...
FooService instance 1 doing something...
FooService instance 2 doing something...
FooService instance 2 doing something...
Scoped instances are same: TrueResolving BarService for the second time:
FooService instance 3 doing something...
FooService instance 3 doing something...
FooService instance 4 doing something...
FooService instance 4 doing something...
Scoped instances are same: TrueResolving IFooService directly:
FooService instance 1 doing something...
FooService instance 1 doing something...
Singleton instances are same: True

从输出中可以看出:

  • 在同一个作用域内,两次解析得到的 IFooService 实例是相同的。
  • 在不同的作用域内,两次解析得到的 IFooService 实例是不同的。
  • 单例(Singleton)实例在整个应用程序生命周期内只有一个实例。

 四、总结

        这个一个手写IOC容器的简单示例,可以清晰地了解IOC容器地实现原理及作用,希望该示例能帮助大家理解IOC容器地原理以及去手写实现逻辑,验证单例、瞬时和作用域实例的生命周期等。


http://www.mrgr.cn/news/63067.html

相关文章:

  • 如何使用java雪花算法在分布式环境中生成唯一ID?
  • SemiDrive E3 多核心运行 FreeRTOS 配置介绍
  • 什么是RabbitMQ
  • 大数据导论第八章作业
  • aws(学习笔记第八课) 使用AWS的S3,ACL和存储桶策略
  • NLP算法工程师精进之路:顶会论文研读精华
  • 【C++】类和对象(九):再谈构造函数
  • python画图|errorbar初探
  • 鸿蒙NEXT开发笔记(九)仿微信聊天App的收发文本消息
  • 无人机救援系统基本组成
  • 选项卡设计与实现
  • Python酷库之旅-第三方库Pandas(183)
  • [数组基础] 0724. 寻找数组的中心下标
  • 机器学习算法之回归算法
  • Java中跳转结构
  • 实系数多项式的运算算法
  • <HarmonyOS第一课>HarmonyOS SDK开放能力简介的课后习题
  • 用示波器如何调方波?
  • 11-Python基础编程之错误和异常
  • HTML 事件
  • 深入理解 Java UUID 五个版本的区别及使用场景
  • PMP–知识卡片--项目经理领导风格
  • Partition架构
  • 荒野大嫖客:救赎 MagicRDR拆包工具简体中文汉化版1.3.6.3
  • Edge 浏览器特别好用的几个插件
  • 【JS学习】04. JS基础语法-函数