Add an reflection method in machine

This commit is contained in:
luosheng
2023-03-28 19:04:50 +08:00
parent c20809c3fb
commit 1778bd59a0
8 changed files with 82 additions and 27 deletions

View File

@@ -1,7 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Modbus.Net.Modbus.SelfDefinedSample

View File

@@ -1,8 +1,5 @@
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Modbus.Net.Modbus.SelfDefinedSample

View File

@@ -28,7 +28,7 @@ namespace Modbus.Net.Modbus
/// 读输入寄存器
/// </summary>
ReadInputRegister = 4,
/// <summary>
/// 写单个线圈
/// </summary>

View File

@@ -13,7 +13,7 @@ namespace Modbus.Net
/// 设备的抽象
/// </summary>
/// <typeparam name="TKey"></typeparam>
public interface IMachine<TKey> : IMachineProperty<TKey>, IMachineMethodData where TKey : IEquatable<TKey>
public interface IMachine<TKey> : IMachineProperty<TKey>, IMachineMethodData, IMachineReflectionCall where TKey : IEquatable<TKey>
{
}
}

View File

@@ -0,0 +1,29 @@
using System.Threading.Tasks;
namespace Modbus.Net
{
/// <summary>
/// 设备的反射调用接口
/// </summary>
public interface IMachineReflectionCall
{
/// <summary>
/// 反射方式调用获取方法
/// </summary>
/// <typeparam name="T">要返回的数据类型</typeparam>
/// <param name="functionName">方法名</param>
/// <param name="parameters">参数</param>
/// <returns>返回的数据</returns>
Task<ReturnStruct<T>> InvokeGet<T>(string functionName, object[] parameters);
/// <summary>
/// 反射方式调用设置方法
/// </summary>
/// <typeparam name="T">要设置的数据类型</typeparam>
/// <param name="functionName">方法名</param>
/// <param name="parameters">参数</param>
/// <param name="datas">要设置的数据</param>
/// <returns>设置是否成功</returns>
Task<ReturnStruct<bool>> InvokeSet<T>(string functionName, object[] parameters, T datas);
}
}

View File

@@ -145,9 +145,10 @@ namespace Modbus.Net
/// <param name="queryId">任务ID每个触发器唯一</param>
/// <param name="machine">要获取数据的设备实例</param>
/// <param name="machineDataType">获取数据的方式</param>
/// <param name="callFunction">调用函数的名称</param>
/// <returns></returns>
/// <exception cref="NullReferenceException"></exception>
public async Task<MachineQueryJobScheduler> From(string queryId, IMachineMethodData machine, MachineDataType machineDataType)
public async Task<MachineQueryJobScheduler> From(string queryId, IMachineReflectionCall machine, MachineDataType machineDataType, string callFunction = "Datas")
{
JobKey jobKey = JobKey.Create("Modbus.Net.DataQuery.Job." + queryId, "Modbus.Net.DataQuery.Group." + _trigger.Key.Name);
@@ -158,6 +159,7 @@ namespace Modbus.Net
job.JobDataMap.Put("DataType", machineDataType);
job.JobDataMap.Put("Machine", machine);
job.JobDataMap.Put("Function", callFunction);
if (_parentJobKey != null)
{
@@ -351,9 +353,10 @@ namespace Modbus.Net
/// </summary>
/// <param name="queryId">任务ID每个触发器唯一</param>
/// <param name="machine">写入数据的设备实例</param>
/// <param name="callFunction">调用函数的名称</param>
/// <returns></returns>
/// <exception cref="NullReferenceException"></exception>
public async Task<MachineDealJobScheduler> To(string queryId, IMachineMethodData machine)
public async Task<MachineDealJobScheduler> To(string queryId, IMachineReflectionCall machine, string callFunction = "Datas")
{
JobKey jobKey = JobKey.Create("Modbus.Net.DataQuery.Job." + queryId, "Modbus.Net.DataQuery.Group." + _trigger.Key.Name);
@@ -363,6 +366,7 @@ namespace Modbus.Net
.Build();
job.JobDataMap.Put("Machine", machine);
job.JobDataMap.Put("Function", callFunction);
var listener = _scheduler.ListenerManager.GetJobListener("Modbus.Net.DataQuery.Chain." + _trigger.Key.Name) as JobChainingJobListenerWithDataMap;
if (listener == null) throw new NullReferenceException("Listener " + "Modbus.Net.DataQuery.Chain." + _trigger.Key.Name + " is null");
@@ -379,10 +383,11 @@ namespace Modbus.Net
/// <param name="queryId">任务ID每个触发器唯一</param>
/// <param name="machine">要获取数据的设备实例</param>
/// <param name="machineDataType">获取数据的方式</param>
/// <param name="callFunction">调用函数的名称</param>
/// <returns></returns>
public async Task<MachineQueryJobScheduler> From(string queryId, IMachineMethodData machine, MachineDataType machineDataType)
public async Task<MachineQueryJobScheduler> From(string queryId, IMachineReflectionCall machine, MachineDataType machineDataType, string callFunction = "Datas")
{
return await new MachineGetJobScheduler(_scheduler, _trigger, _parentJobKey).From(queryId, machine, machineDataType);
return await new MachineGetJobScheduler(_scheduler, _trigger, _parentJobKey).From(queryId, machine, machineDataType, callFunction);
}
/// <summary>
@@ -476,9 +481,11 @@ namespace Modbus.Net
{
object machine;
object machineDataType;
object callFunction;
context.JobDetail.JobDataMap.TryGetValue("Machine", out machine);
context.JobDetail.JobDataMap.TryGetValue("DataType", out machineDataType);
var values = await (machine as IMachineMethodData)!.GetDatasAsync((MachineDataType)machineDataType);
context.JobDetail.JobDataMap.TryGetValue("Function", out callFunction);
var values = await (machine as IMachineReflectionCall)!.InvokeGet<Dictionary<string, ReturnUnit>>((string)callFunction, new object[] { (MachineDataType)machineDataType });
context.JobDetail.JobDataMap.Put("Value", values);
await context.Scheduler.AddJob(context.JobDetail, true, false);
@@ -522,10 +529,12 @@ namespace Modbus.Net
object machineDataType;
object values;
object valuesSet;
object callFunction;
context.JobDetail.JobDataMap.TryGetValue("Machine", out machine);
context.JobDetail.JobDataMap.TryGetValue("DataType", out machineDataType);
context.JobDetail.JobDataMap.TryGetValue("Value", out values);
context.JobDetail.JobDataMap.TryGetValue("SetValue", out valuesSet);
context.JobDetail.JobDataMap.TryGetValue("Function", out callFunction);
if (valuesSet == null && values != null)
valuesSet = ((ReturnStruct<Dictionary<string, ReturnUnit>>)values).Datas.MapGetValuesToSetValues();
@@ -534,7 +543,7 @@ namespace Modbus.Net
context.JobDetail.JobDataMap.Put("Success", false);
return;
}
var success = await (machine as IMachineMethodData)!.SetDatasAsync((MachineDataType)machineDataType, (Dictionary<string, double>)valuesSet);
var success = await (machine as IMachineReflectionCall)!.InvokeSet((string)callFunction, new object[] { (MachineDataType)machineDataType }, (Dictionary<string, double>)valuesSet);
context.JobDetail.JobDataMap.Put("Success", success);
}

View File

@@ -76,7 +76,7 @@ namespace Modbus.Net
/// </summary>
/// <typeparam name="TKey">设备的Id类型</typeparam>
/// <typeparam name="TUnitKey">设备中使用的AddressUnit的Id类型</typeparam>
public abstract class BaseMachine<TKey, TUnitKey> : IMachine<TKey>
public abstract class BaseMachine<TKey, TUnitKey> : IMachine<TKey>, IMachineReflectionCall
where TKey : IEquatable<TKey>
where TUnitKey : IEquatable<TUnitKey>
{
@@ -665,6 +665,39 @@ namespace Modbus.Net
return null;
}
/// <summary>
/// 获取Utility的执行方法
/// </summary>
/// <typeparam name="TUtilityMethod">Utility实现的接口名称</typeparam>
/// <returns></returns>
public TUtilityMethod GetUtilityMethods<TUtilityMethod>() where TUtilityMethod : class, IUtilityMethod
{
return BaseUtility as TUtilityMethod;
}
/// <inheritdoc />
public async Task<ReturnStruct<T>> InvokeGet<T>(string functionName, object[] parameters)
{
var machineMethodType = GetType();
var machineMethod = this as IMachineMethod;
var machineSetMethod = machineMethodType.GetMethod("Get" + functionName + "Async");
var ans = machineSetMethod.Invoke(machineMethod, parameters);
return await (Task<ReturnStruct<T>>)ans;
}
/// <inheritdoc />
public async Task<ReturnStruct<bool>> InvokeSet<T>(string functionName, object[] parameters, T datas)
{
var machineMethodType = GetType();
var machineMethod = this as IMachineMethod;
var machineSetMethod = machineMethodType.GetMethod("Set" + functionName + "Async");
object[] allParams = new object[parameters.Length + 1];
Array.Copy(parameters, allParams, parameters.Length);
allParams[parameters.Length] = datas;
var ans = machineSetMethod.Invoke(machineMethod, allParams);
return await (Task<ReturnStruct<bool>>)ans;
}
/// <summary>
/// 连接设备
/// </summary>
@@ -709,16 +742,6 @@ namespace Modbus.Net
return null;
}
}
/// <summary>
/// 获取Utility
/// </summary>
/// <typeparam name="TUtilityMethod">Utility实现的接口名称</typeparam>
/// <returns></returns>
public TUtilityMethod GetUtility<TUtilityMethod>() where TUtilityMethod : class, IUtilityMethod
{
return BaseUtility as TUtilityMethod;
}
}
internal class BaseMachineEqualityComparer<TKey> : IEqualityComparer<IMachineProperty<TKey>>

View File

@@ -11,7 +11,7 @@ namespace Modbus.Net.Tests
public void GetUtility()
{
BaseMachine<int, int> baseMachine = new ModbusMachine<int, int>(1, ModbusType.Tcp, "192.168.3.12", null, true, 2, 0);
var utility = baseMachine.GetUtility<IUtilityMethodData>();
var utility = baseMachine.GetUtilityMethods<IUtilityMethodData>();
var methods = utility.GetType().GetRuntimeMethods();
Assert.AreEqual(methods.FirstOrDefault(method => method.Name == "GetDataAsync") != null, true);
Assert.AreEqual(methods.FirstOrDefault(method => method.Name == "SetDataAsync") != null, true);
@@ -22,7 +22,7 @@ namespace Modbus.Net.Tests
public async Task InvokeUtility()
{
BaseMachine<int, int> baseMachine = new ModbusMachine<int, int>(1, ModbusType.Tcp, "192.168.3.12", null, true, 2, 0);
var success = await baseMachine.BaseUtility.GetUtilityMethods<IUtilityMethodData>().SetDatasAsync("4X 1", new object[] {(byte)11});
var success = await baseMachine.BaseUtility.GetUtilityMethods<IUtilityMethodData>().SetDatasAsync("4X 1", new object[] { (byte)11 });
Assert.AreEqual(success, true);
var datas = await baseMachine.BaseUtility.GetUtilityMethods<IUtilityMethodData>().GetDatasAsync("4X 1", 1);
Assert.AreEqual(datas.Datas[0], 11);