799 lines
35 KiB
C#
799 lines
35 KiB
C#
using ATS.Models;
|
||
using ATS.Tools;
|
||
using ATS.Views;
|
||
using ATS.Windows;
|
||
using ATS_DBContext;
|
||
using ATS_DBContext.Models;
|
||
using ControlzEx.Standard;
|
||
using MaterialDesignThemes.Wpf;
|
||
using System;
|
||
using System.Collections;
|
||
using System.Collections.Generic;
|
||
using System.Diagnostics;
|
||
using System.Linq;
|
||
using System.Reflection;
|
||
using System.Reflection.Metadata;
|
||
using System.Security.Cryptography;
|
||
using System.Text;
|
||
using System.Threading.Tasks;
|
||
using System.Windows;
|
||
using static ATS.Models.ParameterModel;
|
||
|
||
namespace ATS.Logic
|
||
{
|
||
public static class StepRunning
|
||
{
|
||
private static readonly Dictionary<Guid, ParameterModel> tmpParameters = [];
|
||
|
||
private static readonly Stopwatch stepStopwatch = new();
|
||
|
||
private static readonly Stack<Stopwatch> loopStopwatchStack = new();
|
||
|
||
private static readonly Stack<LoopContext> loopStack = new();
|
||
|
||
public static CancellationTokenSource stepCTS = new();
|
||
private static bool SubSingleStep = false;
|
||
|
||
private static Guid TestRoundID;
|
||
|
||
public static async Task<bool> ExecuteSteps(ProgramModel program, int depth = 0, CancellationToken cancellationToken = default, string subProgramPath = "")
|
||
{
|
||
int index = 0;
|
||
bool overallSuccess = true;
|
||
var ReportList = ReportModelList.ReportList;
|
||
if (ReportList == null)
|
||
{
|
||
ReportList = new List<ReportModel>();
|
||
}
|
||
|
||
if (depth == 0)
|
||
{
|
||
loopStack.Clear();
|
||
loopStopwatchStack.Clear();
|
||
ResetAllStepStatus(program);
|
||
tmpParameters.Clear();
|
||
TestRoundID = Guid.NewGuid();
|
||
}
|
||
foreach (var item in program.Parameters)
|
||
{
|
||
tmpParameters.TryAdd(item.ID, item);
|
||
}
|
||
|
||
while (index < program.StepCollection.Count)
|
||
{
|
||
while (ToolBar.Instance.IsStop == true)
|
||
{
|
||
await Task.Delay(50);
|
||
}
|
||
if (cancellationToken.IsCancellationRequested)
|
||
{
|
||
break;
|
||
}
|
||
var step = program.StepCollection[index];
|
||
if (!step.IsUsed)
|
||
{
|
||
index++;
|
||
continue;
|
||
}
|
||
|
||
step.Result = 0;
|
||
if (step.StepType == "循环开始")
|
||
{
|
||
var endStep = program.StepCollection.FirstOrDefault(x => x.LoopStartStepId == step.ID);
|
||
if (endStep != null)
|
||
{
|
||
endStep.Result = 0;
|
||
}
|
||
else
|
||
{
|
||
Log.Error("程序循环指令未闭合,请检查后重试");
|
||
break;
|
||
}
|
||
}
|
||
|
||
// 处理循环开始
|
||
if (step.StepType == "循环开始")
|
||
{
|
||
Stopwatch loopStopwatch = new();
|
||
loopStopwatch.Start();
|
||
loopStopwatchStack.Push(loopStopwatch);
|
||
var context = new LoopContext
|
||
{
|
||
LoopCount = step.LoopCount ?? 1,
|
||
CurrentLoop = 0,
|
||
StartIndex = index,
|
||
LoopStartStep = step
|
||
};
|
||
loopStack.Push(context);
|
||
step.CurrentLoopCount = context.LoopCount;
|
||
Log.Info($"循环开始,共{context.LoopCount}次", depth);
|
||
index++;
|
||
}
|
||
|
||
// 处理循环结束
|
||
else if (step.StepType == "循环结束")
|
||
{
|
||
if (loopStack.Count == 0)
|
||
{
|
||
Log.Error("未匹配的循环结束指令", depth);
|
||
step.Result = 2;
|
||
index++;
|
||
continue;
|
||
}
|
||
|
||
var context = loopStack.Peek();
|
||
context.CurrentLoop++;
|
||
|
||
// 更新循环开始步骤的显示
|
||
context.LoopStartStep!.CurrentLoopCount = context.LoopCount - context.CurrentLoop;
|
||
|
||
if (context.CurrentLoop < context.LoopCount)
|
||
{
|
||
// 继续循环:跳转到循环开始后的第一条指令
|
||
index = context.StartIndex + 1;
|
||
Log.Info($"循环第{context.CurrentLoop}次结束,跳回开始,剩余{context.LoopCount - context.CurrentLoop}次", depth);
|
||
}
|
||
else
|
||
{
|
||
// 循环结束
|
||
loopStack.Pop();
|
||
var loopStopwatch = loopStopwatchStack.Peek();
|
||
index++;
|
||
Log.Info($"循环结束,共执行{context.LoopCount}次", depth);
|
||
if (depth == 0 && loopStopwatch.IsRunning)
|
||
{
|
||
loopStopwatch.Stop();
|
||
step.RunTime = (int)loopStopwatch.ElapsedMilliseconds;
|
||
step.Result = 1;
|
||
program.StepCollection.First(x => x.ID == step.LoopStartStepId).Result = 1;
|
||
loopStopwatchStack.Pop();
|
||
}
|
||
}
|
||
}
|
||
|
||
// 处理普通步骤
|
||
else
|
||
{
|
||
if (depth == 0)
|
||
{
|
||
stepStopwatch.Restart();
|
||
}
|
||
|
||
if (step.SubProgram != null)
|
||
{
|
||
if (ToolBar.Instance.SingleStep)//子程序的单步执行将执行完保存下的所有Method
|
||
{
|
||
SubSingleStep = true;
|
||
ToolBar.Instance.SingleStep = false;
|
||
}
|
||
|
||
// 构建子程序路径
|
||
string currentSubProgramPath = string.IsNullOrEmpty(subProgramPath)
|
||
? step.Name!
|
||
: $"{subProgramPath} -> {step.Name}";
|
||
|
||
Log.Info($"开始执行子程序 [ {step.Index} ] [ {step.Name} ] ", depth);
|
||
|
||
// 传递子程序路径给下一级
|
||
bool subProgramSuccess = await ExecuteSteps(step.SubProgram, depth + 1, cancellationToken, currentSubProgramPath);
|
||
|
||
UpdateCurrentStepResult(step, true, subProgramSuccess, depth);
|
||
overallSuccess &= subProgramSuccess;
|
||
|
||
// 新增:在子程序执行完成后,插入一个总结行
|
||
if (string.IsNullOrEmpty(subProgramPath) && !subProgramPath.Contains(" -> ")) // 如果是子程序内部执行完成(即不是主程序),才插入总结行
|
||
{
|
||
ReportModelList.ReportList.Add(new ReportModel
|
||
{
|
||
stepModel = new StepModel()
|
||
{
|
||
Index = -1,
|
||
Name = $"子程序 [{step.Name}] 执行结果:{(subProgramSuccess ? "PASS" : "FAIL")}"
|
||
}, // 没有对应的实际步骤,这里用于装在结果
|
||
User = null,
|
||
ExcuteTime = null,
|
||
IsPass = subProgramSuccess ? IsPass.PASS : IsPass.FAIL,
|
||
Result = "",
|
||
SubProgramPath = "",
|
||
IsSubProgramSummary = true,
|
||
SubProgramName = ""
|
||
});
|
||
|
||
Log.Success($"子程序 [{step.Name}] 总结行已写入");
|
||
}
|
||
|
||
if (SubSingleStep)
|
||
{
|
||
SubSingleStep = false;
|
||
ToolBar.Instance.SingleStep = true;
|
||
}
|
||
}
|
||
else if (step.Method != null)
|
||
{
|
||
Log.Info($"开始执行指令 [ {step.Index} ] [ {step.Method!.FullName}.{step.Method.Name} ] ", depth);
|
||
await ExecuteMethodStep(step, tmpParameters, depth, cancellationToken, subProgramPath); // 传递路径
|
||
bool stepSuccess = step.Result == 1;
|
||
overallSuccess &= stepSuccess;
|
||
|
||
if (step.NGGotoStepID != null && !stepSuccess)
|
||
{
|
||
var tmp = program.StepCollection.FirstOrDefault(x => x.ID == step.NGGotoStepID);
|
||
if (tmp != null)
|
||
{
|
||
index = tmp.Index - 2;
|
||
Log.Info($"指令跳转 [ {tmp.Index} ] [ {tmp.Name} ]", depth);
|
||
}
|
||
}
|
||
if (step.OKGotoStepID != null && stepSuccess)
|
||
{
|
||
var tmp = program.StepCollection.FirstOrDefault(x => x.ID == step.OKGotoStepID);
|
||
if (tmp != null)
|
||
{
|
||
index = tmp.Index - 2;
|
||
Log.Info($"指令跳转 [ {tmp.Index} ] [ {tmp.Name} ]", depth);
|
||
}
|
||
}
|
||
}
|
||
index++;
|
||
|
||
if (ToolBar.Instance.SingleStep||step.isBrokenpoint==true)
|
||
{
|
||
ToolBar.Instance.IsStop = true;
|
||
ToolBar.Instance.RunState = "运行";
|
||
ToolBar.Instance.RunIcon = PackIconKind.Play;
|
||
}
|
||
}
|
||
}
|
||
|
||
bool finalResult = loopStack.Count == 0 && overallSuccess;
|
||
|
||
if (depth > 0) // 子程序
|
||
{
|
||
return finalResult;
|
||
}
|
||
|
||
return finalResult;
|
||
}
|
||
|
||
public static async Task ExecuteMethodStep(StepModel step, Dictionary<Guid, ParameterModel> parameters, int depth, CancellationToken cancellationToken = default, string subProgramPath = "")
|
||
{
|
||
try
|
||
{
|
||
MainWindow.Instance.SelectedStep = null;
|
||
await Task.Delay(SystemConfig.Instance.PerformanceLevel);
|
||
|
||
// 1. 查找类型
|
||
Type? targetType = null;
|
||
foreach (var assembly in CommandTreeView.Instance!.Assemblies)
|
||
{
|
||
targetType = assembly.GetType(step.Method!.FullName!);
|
||
if (targetType != null) break;
|
||
}
|
||
if (targetType == null)
|
||
{
|
||
Log.Error($"指令 [ {step.Index} ] 执行错误:未找到类型 {step.Method!.FullName}", depth);
|
||
step.Result = 2;
|
||
}
|
||
|
||
// 2. 创建实例(仅当方法不是静态时才需要)
|
||
object? instance = null;
|
||
bool isStaticMethod = false;
|
||
|
||
// 3. 准备参数
|
||
var inputParams = new List<object?>();
|
||
var paramTypes = new List<Type>();
|
||
ParameterModel? outputParam = null;
|
||
foreach (var param in step.Method!.Parameters)
|
||
{
|
||
if (param.Category == ParameterCategory.Input)
|
||
{
|
||
if (param.Type == typeof(CancellationToken))
|
||
{
|
||
inputParams.Add(stepCTS.Token);
|
||
paramTypes.Add(param.Type!);
|
||
continue;
|
||
}
|
||
var actualValue = param.GetActualValue(tmpParameters);
|
||
// 类型转换处理
|
||
if (actualValue != null)
|
||
{
|
||
if (string.IsNullOrEmpty(actualValue.ToString()))
|
||
{
|
||
actualValue = null;
|
||
}
|
||
if (actualValue != null && param.Type != null && actualValue.GetType() != param.Type)
|
||
{
|
||
try
|
||
{
|
||
if (param.Type.IsArray)
|
||
{
|
||
// --- 原有的数组处理逻辑 ---
|
||
// 获取数组元素类型
|
||
Type elementType = param.Type.GetElementType()!;
|
||
|
||
// 解析字符串为字符串数组
|
||
string[] stringArray = actualValue.ToString()!
|
||
.Trim('[', ']')
|
||
.Split(',', StringSplitOptions.RemoveEmptyEntries)
|
||
.Select(s => s.Trim())
|
||
.ToArray();
|
||
|
||
// 创建目标类型数组
|
||
Array array = Array.CreateInstance(elementType, stringArray.Length);
|
||
|
||
// 转换每个元素
|
||
for (int i = 0; i < stringArray.Length; i++)
|
||
{
|
||
try
|
||
{
|
||
// 特殊处理字符串类型
|
||
if (elementType == typeof(string))
|
||
{
|
||
array.SetValue(stringArray[i], i);
|
||
}
|
||
// 特殊处理枚举类型
|
||
else if (elementType.IsEnum)
|
||
{
|
||
array.SetValue(Enum.Parse(elementType, stringArray[i]), i);
|
||
}
|
||
// 常规类型转换
|
||
{
|
||
if (stringArray[i] is string s && s.StartsWith("0x", StringComparison.OrdinalIgnoreCase))
|
||
{
|
||
// 先转成整数
|
||
var intValue = Convert.ToInt64(s, 16);
|
||
|
||
// 再转成目标类型
|
||
array.SetValue(Convert.ChangeType(intValue, elementType), i);
|
||
}
|
||
else
|
||
{
|
||
array.SetValue(Convert.ChangeType(stringArray[i], elementType), i);
|
||
}
|
||
|
||
}
|
||
}
|
||
catch
|
||
{
|
||
throw new InvalidCastException($"指令 [ {step.Index} ] 执行错误:元素 '{stringArray[i]}' 无法转换为 {elementType.Name}[]");
|
||
}
|
||
}
|
||
actualValue = array;
|
||
}
|
||
// --- 修改:处理 Type 为 object 且 Value 为字符串的情况 ---
|
||
else if (param.Type == typeof(object) && actualValue is string strValue)
|
||
{
|
||
// 尝试将字符串解析为常见的数组类型
|
||
object parsedArray = TryParseStringToCommonArrays(strValue);
|
||
if (parsedArray != null)
|
||
{
|
||
actualValue = parsedArray; // 使用解析出的数组
|
||
}
|
||
// 如果解析失败 (parsedArray is null),actualValue 保持原字符串值
|
||
// 让后续的 Convert.ChangeType 尝试处理 (通常会失败,但这是预期的)
|
||
}
|
||
// --- 原有的非数组类型处理逻辑 ---
|
||
else if (param.Type.BaseType == typeof(Enum))
|
||
{
|
||
actualValue = Enum.Parse(param.Type, actualValue.ToString()!);
|
||
}
|
||
else if(actualValue is string s && s.StartsWith("0x", StringComparison.OrdinalIgnoreCase))
|
||
{
|
||
// 先转成整数
|
||
var intValue = Convert.ToInt64(s, 16);
|
||
|
||
// 再转成目标类型
|
||
actualValue = Convert.ChangeType(intValue, param.Type);
|
||
}
|
||
|
||
else
|
||
{
|
||
actualValue = Convert.ChangeType(actualValue, param.Type);
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Log.Warning($"指令 [ {step.Index} ] 执行错误:参数 {param.Name} 类型转换失败: {ex.Message}", depth);
|
||
// 可以选择在此处记录错误并设置 step.Result,或者继续执行
|
||
// 这里我们选择继续,但实际应用中可能需要更严格的错误处理
|
||
}
|
||
}
|
||
}
|
||
inputParams.Add(actualValue);
|
||
paramTypes.Add(param.Type!);
|
||
}
|
||
else if (param.Category == ParameterCategory.Output)
|
||
{
|
||
outputParam = param;
|
||
}
|
||
}
|
||
|
||
// 4. 获取方法
|
||
var method = targetType!.GetMethod(
|
||
step.Method.Name!,
|
||
BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance,
|
||
null,
|
||
paramTypes.ToArray(),
|
||
null
|
||
);
|
||
|
||
if (method == null)
|
||
{
|
||
Log.Error($"指令 [ {step.Index} ] 执行错误:未找到方法{step.Method.Name}", depth);
|
||
step.Result = 2;
|
||
}
|
||
|
||
// 检查是否是静态方法
|
||
isStaticMethod = method!.IsStatic;
|
||
|
||
// 如果是实例方法,需要创建实例
|
||
if (!isStaticMethod)
|
||
{
|
||
try
|
||
{
|
||
instance = Activator.CreateInstance(targetType);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Log.Error($"指令 [ {step.Index} ] 执行错误:创建实例失败 - {ex.Message}", depth);
|
||
step.Result = 2;
|
||
}
|
||
}
|
||
|
||
// 5. 执行方法
|
||
|
||
object? returnValue = method.Invoke(instance, inputParams.ToArray());
|
||
try
|
||
{
|
||
// 处理异步方法
|
||
if (returnValue is Task task)
|
||
{
|
||
await task.ConfigureAwait(false);
|
||
// 获取结果(如果是Task<T>)
|
||
if (task.GetType().IsGenericType)
|
||
{
|
||
var returnValueProperty = task.GetType().GetProperty("Result");
|
||
returnValue = returnValueProperty?.GetValue(task);
|
||
}
|
||
else
|
||
{
|
||
returnValue = null;
|
||
}
|
||
}
|
||
|
||
// 处理VoidTaskreturnValue类型
|
||
if (returnValue != null && returnValue.GetType().FullName == "System.Threading.Tasks.VoidTaskreturnValue")
|
||
{
|
||
returnValue = null;
|
||
}
|
||
}
|
||
catch (OperationCanceledException)
|
||
{
|
||
return;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Log.Error($"指令 [ {step.Index} ] 执行错误: {ex.InnerException?.Message ?? ex.Message}", depth);
|
||
step.Result = 2;
|
||
|
||
//给报告添加子程序执行结果
|
||
ReportModelList.ReportList.Add(new ReportModel
|
||
{
|
||
stepModel = step,
|
||
User = MainWindow.Instance.User.UserName,
|
||
ExcuteTime = DateTime.Now,
|
||
IsPass = step.Result == 1 ? IsPass.PASS : IsPass.FAIL,
|
||
Result = $"指令 [ {step.Index} ] 执行错误: {ex.InnerException?.Message ?? ex.Message}"
|
||
});
|
||
Log.Success($"指令 [ {step.Index} ]报告已写入");
|
||
return;
|
||
}
|
||
|
||
// 6. 处理输出
|
||
bool paraResult = true;
|
||
string resultMsg = "";
|
||
if (outputParam != null)
|
||
{
|
||
outputParam.Value = returnValue;
|
||
var currentPara = outputParam.GetCurrentParameter(tmpParameters);
|
||
if (currentPara != null)
|
||
{
|
||
currentPara.Value = returnValue;
|
||
var tmp = currentPara.GetResult();
|
||
currentPara.Result = tmp.Item1;
|
||
if (tmp.Item2 != null)
|
||
{
|
||
Log.Warning(tmp.Item2);
|
||
}
|
||
if (currentPara.IsSave && MainWindow.Instance.Program.Parameters.FirstOrDefault(x => x.ID == currentPara.ID) != null)
|
||
{
|
||
_ = SaveDataToDatabase(MainWindow.Instance.Program.ID, currentPara);
|
||
}
|
||
}
|
||
var returnType = returnValue?.GetType();
|
||
if (returnType != null)
|
||
{
|
||
if (!returnType.IsArray)
|
||
{
|
||
Log.Success($"输出 [ {outputParam.Name} ] = {returnValue} ({returnType.Name})", depth);
|
||
// 只有勾选了IsOutputToReport才记录到报告的Result中
|
||
if (outputParam.IsOutputToReport)
|
||
{
|
||
resultMsg = $"输出 [ {outputParam.Name} ] = {returnValue} ({returnType.Name})";
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (returnValue is IEnumerable enumerable)
|
||
{
|
||
var elements = enumerable.Cast<object>().Select(item => item?.ToString() ?? "null");
|
||
Log.Success($"输出 [ {outputParam.Name} ] = [ {string.Join(", ", elements)} ] ({returnType.Name})", depth);
|
||
// 只有勾选了IsOutputToReport才记录到报告的Result中
|
||
if (outputParam.IsOutputToReport)
|
||
{
|
||
resultMsg = $"输出 [ {outputParam.Name} ] = [ {string.Join(", ", elements)} ] ({returnType.Name})";
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
Log.Success($"指令 [ {step.Index} ] 执行成功", depth);
|
||
UpdateCurrentStepResult(step, paraResult: paraResult, depth: depth);
|
||
if (ReportModelList.ReportList == null)
|
||
{
|
||
ReportModelList.ReportList = new List<ReportModel>();
|
||
}
|
||
|
||
// 始终写入报告,但Result内容根据输出参数的IsOutputToReport控制
|
||
ReportModelList.ReportList.Add(new ReportModel
|
||
{
|
||
stepModel = step,
|
||
User = MainWindow.Instance.User.UserName,
|
||
ExcuteTime = DateTime.Now,
|
||
IsPass = step.Result == 1 ? IsPass.PASS : IsPass.FAIL,
|
||
Result = resultMsg, // resultMsg只在IsOutputToReport=true时才有值
|
||
SubProgramPath = subProgramPath
|
||
});
|
||
Log.Success($"指令 [ {step.Index} ]报告已写入");
|
||
|
||
}
|
||
catch (OperationCanceledException)
|
||
{
|
||
return;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Log.Error($"指令 [ {step.Index} ] 执行错误: {ex.InnerException?.Message ?? ex.Message}", depth);
|
||
step.Result = 2;
|
||
return;
|
||
}
|
||
}
|
||
|
||
public static void ResetAllStepStatus(ProgramModel program)
|
||
{
|
||
foreach (var step in program.StepCollection)
|
||
{
|
||
step.Result = -1;
|
||
step.RunTime = null;
|
||
}
|
||
}
|
||
|
||
private static void UpdateCurrentStepResult(StepModel step, bool paraResult = true, bool stepResult = true, int depth = 0)
|
||
{
|
||
if (stepResult && paraResult)
|
||
{
|
||
if (string.IsNullOrEmpty(step.OKExpression))
|
||
{
|
||
step.Result = 1;
|
||
}
|
||
else
|
||
{
|
||
Dictionary<string, object> paraDic = [];
|
||
foreach (var item in tmpParameters)
|
||
{
|
||
paraDic.TryAdd(item.Value.Name, item.Value.Value!);
|
||
}
|
||
if (step.SubProgram != null)
|
||
{
|
||
foreach (var item in step.SubProgram.Parameters.Where(x => x.Category == ParameterCategory.Output))
|
||
{
|
||
paraDic.TryAdd(item.Name, item.Value!);
|
||
}
|
||
}
|
||
else if (step.Method != null)
|
||
{
|
||
foreach (var item in step.Method.Parameters.Where(x => x.Category == ParameterCategory.Output))
|
||
{
|
||
paraDic.TryAdd(item.Name, item.Value!);
|
||
}
|
||
}
|
||
bool re = ExpressionEvaluator.EvaluateExpression(step.OKExpression, paraDic);
|
||
step.Result = re ? 1 : 2;
|
||
if (step.Result == 2)
|
||
{
|
||
Log.Warning($"指令 [ {step.Index} ] FAIL:条件表达式验证失败", depth);
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (!paraResult)
|
||
{
|
||
Log.Warning("参数限值校验失败", depth);
|
||
}
|
||
step.Result = 2;
|
||
}
|
||
}
|
||
|
||
private static async Task SaveDataToDatabase(Guid programID, ParameterModel currentPara)
|
||
{
|
||
using (ATS_DB db = new())
|
||
{
|
||
db.TestData.Add(new()
|
||
{
|
||
ProgramID = programID,
|
||
TestRoundID = TestRoundID,
|
||
ParameterID = currentPara.ID,
|
||
Value = currentPara.Value?.ToString() ?? "",
|
||
LowerLimit = currentPara.LowerLimit?.ToString(),
|
||
UpperLimit = currentPara.UpperLimit?.ToString(),
|
||
Result = currentPara.Result
|
||
});
|
||
try
|
||
{
|
||
var row = await db.SaveChangesAsync().ConfigureAwait(false);
|
||
if (row == 0)
|
||
{
|
||
Log.Error($"测试数据保存失败:未知的错误");
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Log.Error($"测试数据保存失败{ex.InnerException}");
|
||
}
|
||
}
|
||
}
|
||
// 添加一个辅助方法来尝试解析字符串为不同类型的数组
|
||
private static object TryParseStringToCommonArrays(string strValue)
|
||
{
|
||
// 尝试解析常见的数组格式
|
||
strValue = strValue.Trim('[', ']');
|
||
string[] parts = System.Text.RegularExpressions.Regex.Split(strValue, @"[,\s]+").Where(s => !string.IsNullOrEmpty(s)).ToArray();
|
||
|
||
if (parts.Length == 0) return null; // 空数组或无效格式
|
||
|
||
//尝试解析为byte
|
||
if (parts.Length == 1)
|
||
{
|
||
if (byte.TryParse(parts[0], System.Globalization.NumberStyles.Integer, System.Globalization.CultureInfo.InvariantCulture, out byte singleByteValue))
|
||
{
|
||
return singleByteValue;
|
||
}
|
||
}
|
||
|
||
|
||
// --- 新增:先尝试解析为 byte[] (十六进制) ---
|
||
if (TryParseStringArrayToType(parts, out byte[] hexByteResult, s => byte.TryParse(s, System.Globalization.NumberStyles.HexNumber, System.Globalization.CultureInfo.InvariantCulture, out _)))
|
||
{
|
||
return hexByteResult;
|
||
}
|
||
|
||
// --- 新增:再尝试解析为 byte[] (十进制) ---
|
||
if (TryParseStringArrayToType(parts, out byte[] decByteResult, s => byte.TryParse(s, System.Globalization.NumberStyles.Integer, System.Globalization.CultureInfo.InvariantCulture, out _)))
|
||
{
|
||
return decByteResult;
|
||
}
|
||
|
||
// --- 原有的其他类型解析逻辑 ---
|
||
// 尝试解析为 int[]
|
||
if (TryParseStringArrayToType(parts, out int[] intResult, s => int.TryParse(s, System.Globalization.NumberStyles.Integer, System.Globalization.CultureInfo.InvariantCulture, out _)))
|
||
{
|
||
return intResult;
|
||
}
|
||
|
||
// 尝试解析为 double[]
|
||
if (TryParseStringArrayToType(parts, out double[] doubleResult, s => double.TryParse(s, System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out _)))
|
||
{
|
||
return doubleResult;
|
||
}
|
||
|
||
// 尝试解析为 string[] (处理带引号的字符串)
|
||
string[] originalParts = parts; // 保留原始分割结果
|
||
string[] stringParts = originalParts.Select(s => s.Trim('\"', '\'')).ToArray();
|
||
bool allPartsAreNonNumericStrings = stringParts.All(s => !double.TryParse(s, System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out _));
|
||
if (allPartsAreNonNumericStrings && stringParts.All(s => !string.IsNullOrEmpty(s)))
|
||
{
|
||
return stringParts;
|
||
}
|
||
|
||
// 尝试解析为 float[]
|
||
if (TryParseStringArrayToType(parts, out float[] floatResult, s => float.TryParse(s, System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out _)))
|
||
{
|
||
return floatResult;
|
||
}
|
||
|
||
// 尝试解析为 short[]
|
||
if (TryParseStringArrayToType(parts, out short[] shortResult, s => short.TryParse(s, System.Globalization.NumberStyles.Integer, System.Globalization.CultureInfo.InvariantCulture, out _)))
|
||
{
|
||
return shortResult;
|
||
}
|
||
|
||
// 尝试解析为 long[]
|
||
if (TryParseStringArrayToType(parts, out long[] longResult, s => long.TryParse(s, System.Globalization.NumberStyles.Integer, System.Globalization.CultureInfo.InvariantCulture, out _)))
|
||
{
|
||
return longResult;
|
||
}
|
||
|
||
// 尝试解析为 uint[]
|
||
if (TryParseStringArrayToType(parts, out uint[] uintResult, s => uint.TryParse(s, System.Globalization.NumberStyles.Integer, System.Globalization.CultureInfo.InvariantCulture, out _)))
|
||
{
|
||
return uintResult;
|
||
}
|
||
|
||
// 尝试解析为 ushort[]
|
||
if (TryParseStringArrayToType(parts, out ushort[] ushortResult, s => ushort.TryParse(s, System.Globalization.NumberStyles.Integer, System.Globalization.CultureInfo.InvariantCulture, out _)))
|
||
{
|
||
return ushortResult;
|
||
}
|
||
|
||
// 尝试解析为 ulong[]
|
||
if (TryParseStringArrayToType(parts, out ulong[] ulongResult, s => ulong.TryParse(s, System.Globalization.NumberStyles.Integer, System.Globalization.CultureInfo.InvariantCulture, out _)))
|
||
{
|
||
return ulongResult;
|
||
}
|
||
|
||
// 尝试解析为 decimal[]
|
||
if (TryParseStringArrayToType(parts, out decimal[] decimalResult, s => decimal.TryParse(s, System.Globalization.NumberStyles.Number, System.Globalization.CultureInfo.InvariantCulture, out _)))
|
||
{
|
||
return decimalResult;
|
||
}
|
||
|
||
// 尝试解析为 bool[]
|
||
if (TryParseStringArrayToType(parts, out bool[] boolResult, s => bool.TryParse(s, out _)))
|
||
{
|
||
return boolResult;
|
||
}
|
||
|
||
// 如果以上所有尝试都失败,返回 null
|
||
return null;
|
||
}
|
||
|
||
// 一个通用的辅助方法,用于尝试将字符串数组解析为特定类型的数组
|
||
private static bool TryParseStringArrayToType<T>(string[] parts, out T[] result, Func<string, bool> tryParseFunc)
|
||
{
|
||
result = null;
|
||
T[] tempArray = new T[parts.Length];
|
||
for (int i = 0; i < parts.Length; i++)
|
||
{
|
||
if (!tryParseFunc(parts[i]))
|
||
{
|
||
return false; // 解析失败
|
||
}
|
||
// 使用 Convert.ChangeType 确保类型安全
|
||
try
|
||
{
|
||
tempArray[i] = (T)Convert.ChangeType(parts[i], typeof(T), System.Globalization.CultureInfo.InvariantCulture);
|
||
}
|
||
catch
|
||
{
|
||
return false; // 转换失败
|
||
}
|
||
}
|
||
result = tempArray;
|
||
return true; // 解析成功
|
||
}
|
||
|
||
#region 私有类
|
||
|
||
private class LoopContext
|
||
{
|
||
public int LoopCount { get; set; }
|
||
public int CurrentLoop { get; set; }
|
||
public int StartIndex { get; set; }
|
||
public StepModel? LoopStartStep { get; set; }
|
||
}
|
||
|
||
#endregion
|
||
|
||
}
|
||
} |