using BDU.Models; using BDU.Tools; using BDU.Views; using BDU.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 BDU.Models.ParameterModel; namespace BDU.Logic { public static class StepRunning { private static readonly Dictionary tmpParameters = []; private static readonly Stopwatch stepStopwatch = new(); private static readonly Stack loopStopwatchStack = new(); private static readonly Stack loopStack = new(); public static CancellationTokenSource stepCTS = new(); private static bool SubSingleStep = false; private static Guid TestRoundID; public static async Task 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(); } 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 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(); var paramTypes = new List(); 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) 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().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(); } // 始终写入报告,但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 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(string[] parts, out T[] result, Func 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 } }