# Miao.NetCore **Repository Path**: miaolove/miao.-net-core ## Basic Information - **Project Name**: Miao.NetCore - **Description**: 用于NetCore的各种框架和工具编写 - **Primary Language**: C# - **License**: MulanPSL-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 4 - **Forks**: 1 - **Created**: 2022-03-28 - **Last Updated**: 2025-12-22 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 反射抽象泛型调度器 ### 一、设计思想 #### 1.1 抽象类是什么 C#语言中,用abstract 关键字来修饰一个类时,这个类叫作抽象类。抽象类是它的所有子类的公共属性的集合,是包含一个或多个抽象方法的类。抽象类可以看作是对类的进一步抽象。在面向对象领域,抽象类主要用来进行类型隐藏 #### 1.2 为什么要用抽象类 1. 无法完整描述一个类,只能抽象化概念来使用; 2. 子类写的方法重写父类的方法abstact。 #### 1.3 为什么要用泛型 1. 保证了类型的安全性:泛型约束了变量的类型,保证了类型的安全性; 2. 避免了不必要的装箱、拆箱操作,提高程序的性能:泛型变量固定了类型,使用的时候就已经知道是值类型还是引用类型,避免了不必要的装箱、拆箱操作 ### 二、代码基础实现 #### 1.构建泛型抽象类 ​ 经过以上抽象和泛型思想,就有了以下产物,参数可以传入非固定类型,父类处理公共数据,子类处理业务节点细节数据; 父类: ```C# /// /// 实现基类 /// /// public abstract class BaseRealization : IEventHandler where TEvent : Event { public Task HandleAsync(TEvent @event) { try { return Task.Run(() => Receive(@event)); } catch (Exception ex) { throw; } } /// /// 调度处理中心 /// /// public void Handle(TEvent @Event) { try { Receive(@Event); } catch (Exception ex) { throw ex; } } /// /// 节点处理消息 /// /// 消息体 protected abstract void Receive(TEvent eEvent); } ``` #### 2.构建子类行为实现 子类实现各自的细节行为逻辑 子类代码: ```C# /// /// 测试实现 /// [FlowNode("FlowNode1")] public class TestRealization : BaseRealization { /// /// Test接收处理实现 /// /// protected override void Receive(TestParameter eEvent) { var json = JsonConvert.SerializeObject(eEvent); Console.WriteLine($"**********Test**********"); Console.WriteLine($"Test 被实现了,参数name为{eEvent.TestName}"); Console.WriteLine($"**********Test**********\r\n"); } } ``` #### 3.泛型约束 为了使我们泛型类代码有对应公共参数,于是添加了泛型约束类 泛型约束类代码: ```C# /// /// 事件 /// public class Event : IEvent { /// /// 初始化事件 /// public Event() { Id = Guid.NewGuid().ToString(); Time = DateTime.Now; } /// /// 事件标识 /// public string Id { get; set; } /// /// 事件时间 /// public DateTime Time { get; } } ``` #### 4.添加触发事件接口 为了提供给外部使用,于是我们给抽象类提供了调度接口: 抽象泛型接口代码 : ```C# /// /// 事件处理器 /// /// 事件类型 public interface IEventHandler : IEventHandler where TEvent : IEvent { /// /// 异步处理事件 /// /// 事件 Task HandleAsync(TEvent @event); /// /// 处理事件 /// /// 事件 void Handle(TEvent @event); } ``` ### 三、反射调度 #### 1.添加特性 首先,我们需要知道哪些类属于我们业务需要调度的类,于是我们在反射时添加了特性,用于查找当前业务的节点实现,然后通过在首次启动创建,并在特性中设置节点名称FlowNodeName,方便后续可用于调度,Index表示同节点有多个流程,可使用index进行排序调度,当然也可以根据数据库中进行配置排序 特性代码: ```C# /// /// 节点特性 /// public class FlowNodeAttribute : Attribute { /// /// 节点名称 /// public string FlowNodeName { get; set; } /// /// 当节点下有排序实现 /// public int Index { get; set; } = 0; /// /// /// /// public FlowNodeAttribute(string flowNodeName, int index = 0) { FlowNodeName = flowNodeName; Index = index; } } ``` #### 2.反射创建实例 通过以上步骤,相当于实现了知道哪些节点需要执行的,那么我们通过反射加载对应的实现到内存之中,后续可通过节点调度对应实现 反射创建对象代码: ```C# /// /// 节点对应实现字典 /// 使用线程安全字典存放,防止多线程问题 /// public static ConcurrentDictionary RealizationDictionary = new ConcurrentDictionary(); /// /// 参数对应字典 /// 使用线程安全字典存放,防止多线程问题 /// public static ConcurrentDictionary> ParameterDictionary = new ConcurrentDictionary>(); /// /// 初始化 /// private void BaseBusInit() { System.Reflection.Assembly[] allAssembly = AppDomain.CurrentDomain.GetAssemblies(); System.Reflection.Assembly.GetExecutingAssembly(); List realizationTypes = new List(); Assembly.GetAssembly(typeof(IEventHandler<>)); foreach (Assembly assembly in allAssembly) { var types = assembly.GetTypes().Where(x => (x?.BaseType?.IsGenericType ?? false) && x.GetInterfaces().Count() > 0).ToList(); realizationTypes.AddRange(types); } foreach (var realizationType in realizationTypes) { var genericArguments = realizationType.BaseType.GetGenericArguments(); if (genericArguments == null || !genericArguments.Any()) continue; var attributions = realizationType.GetCustomAttributes(typeof(FlowNodeAttribute), false); if (attributions == null || attributions.Length == 0) continue; var attribution = attributions[0] as FlowNodeAttribute; if (attribution == null || string.IsNullOrWhiteSpace(attribution.FlowNodeName)) continue; var flowNodeName = attribution.FlowNodeName; var index = attribution.Index; var reflectionClassInfo = ReflectionClassInfo.CreateInstance(realizationType, index); if (!RealizationDictionary.ContainsKey(flowNodeName)) RealizationDictionary.TryAdd(flowNodeName, reflectionClassInfo); var argFirst = reflectionClassInfo.GenericArguments.FirstOrDefault(); if (argFirst != null) { var parameterClassInfos = new List() { new ParameterClassInfo() { FlowNodeName = flowNodeName, ReflectionClassInfo = reflectionClassInfo } }; var argFirstName = argFirst.FullName; if (ParameterDictionary.ContainsKey(argFirstName)) { List value = ParameterDictionary[argFirstName]; if (value == null) continue; var valueFirst = value.FirstOrDefault(x => x.FlowNodeName == flowNodeName); if (valueFirst != null) continue; value.AddRange(parameterClassInfos); ParameterDictionary[argFirstName] = value; } else ParameterDictionary.TryAdd(argFirstName, parameterClassInfos); } } } ``` #### 3.调度发布 经过以上步骤,那我们就可以根据传入参数进行调度了 ```C# static void Main(string[] args) { try { var baseBus = BaseBus.GetInstance(); baseBus.Publish(new TestParameter() { TestName = "123" }); baseBus.Publish(new Test2Parameter() { TestName = "234" }); } catch (Exception e) { Console.WriteLine(e.Message); } Console.WriteLine("Hello World!"); } /// /// 消息发布 /// /// /// public void Publish(T msg) where T : Event { try { var argName = typeof(T).FullName; if (ParameterDictionary.ContainsKey(argName)) { List value = ParameterDictionary[argName]; if (value == null || !value.Any()) return; var parameters = value.OrderBy(x => x.ReflectionClassInfo.Index).ToList(); foreach (var parameter in parameters) { var type = new Type[] { typeof(T), parameter.ReflectionClassInfo.ClassType }; this.FastInvoke(type, x => x.ConsumerTo>(msg, parameter.FlowNodeName), new object[] { msg, parameter.FlowNodeName }); StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine($"*********调度中心数据************"); stringBuilder.AppendLine($"获取到节点{parameter.FlowNodeName}"); stringBuilder.AppendLine($"获取到节点请求参数{JsonConvert.SerializeObject(msg)}"); stringBuilder.AppendLine($"节点运行结束,状态正常"); stringBuilder.AppendLine($"*********调度中心数据************"); Console.WriteLine(stringBuilder); } } //TODO:此处可以获取节点运行的情况,获取对应节点是否执行完成 //也可以根据节点自动更新节点组数组 } catch (Exception e) { Console.WriteLine("节点运行异常\r\n"); ///记录节点运行异常 throw e; } } ``` ### 四、运行结果 运行结果中,我们可以看到只需要一行代码,我们可实现对应的细节实现调度,并且我们可以监控到对应实现的运行状态; ![实现结果](F:\个人工具资料\Miao.NetCore\miao.-net-core\设计模式\ConsoleDispatch\实现结果.png)