using System.Reflection; using MyParking.Simulation.Core; namespace MyParking.Simulation.Commands; /// /// 自动发现带SimulationAction特性的测试方法并分发网页命令。 /// public sealed class SimulationCommandDispatcher { private readonly SimulationWorld _world; private readonly IReadOnlyDictionary _actions; public SimulationCommandDispatcher( SimulationWorld world) { _world = world; _actions = DiscoverActions(); } /// /// 返回网页动态生成按钮所需的全部命令。 /// public IReadOnlyList GetActions() { return _actions.Values .Select(action => action.Descriptor) .OrderBy(action => action.Group) .ThenBy(action => action.Order) .ToArray(); } /// /// 对指定车辆执行一个已注册的测试方法。 /// public CommandResult Execute( int vehicleId, string command) { if (!_actions.TryGetValue( command, out var registeredAction)) { return new CommandResult( false, $"未注册仿真命令:{command}。"); } try { return _world.WithVehicle(vehicleId, vehicle => { var success = registeredAction.Handler(vehicle); var message = success ? $"车辆{vehicleId}已执行:{registeredAction.Descriptor.DisplayName}。" : $"车辆{vehicleId}暂时无法执行:{registeredAction.Descriptor.DisplayName}。"; return new CommandResult(success, message); }); } catch (KeyNotFoundException exception) { return new CommandResult( false, exception.Message); } } private static IReadOnlyDictionary DiscoverActions() { var actions = new Dictionary( StringComparer.OrdinalIgnoreCase); var methods = Assembly.GetExecutingAssembly() .GetTypes() .SelectMany(type => type.GetMethods( BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static)); foreach (var method in methods) { var attribute = method.GetCustomAttribute(); if (attribute == null) continue; ValidateMethod(method, attribute); var handler = (Func)method.CreateDelegate( typeof(Func)); var descriptor = new SimulationActionDescriptor( attribute.Key, attribute.DisplayName, attribute.Group, attribute.Order); if (!actions.TryAdd( attribute.Key, new RegisteredAction(descriptor, handler))) { throw new InvalidOperationException( $"仿真命令Key重复:{attribute.Key}。"); } } return actions; } private static void ValidateMethod( MethodInfo method, SimulationActionAttribute attribute) { var parameters = method.GetParameters(); if (method.ReturnType != typeof(bool) || parameters.Length != 1 || parameters[0].ParameterType != typeof(SimulationVehicle)) { throw new InvalidOperationException( $"[{nameof(SimulationActionAttribute)}]方法" + $"{method.DeclaringType?.FullName}.{method.Name}" + "必须是static bool Xxx(SimulationVehicle vehicle)。"); } if (string.IsNullOrWhiteSpace(attribute.Key) || string.IsNullOrWhiteSpace(attribute.DisplayName) || string.IsNullOrWhiteSpace(attribute.Group)) { throw new InvalidOperationException( $"仿真命令{method.Name}的特性参数不能为空。"); } } private sealed record RegisteredAction( SimulationActionDescriptor Descriptor, Func Handler); } /// /// 网页测试命令的执行结果。 /// public sealed record CommandResult( bool Success, string Message);