添加单车底盘仿真平台并完善运动控制与夹臂功能
This commit is contained in:
@@ -0,0 +1,150 @@
|
||||
using System.Reflection;
|
||||
using MyParking.Simulation.Core;
|
||||
|
||||
namespace MyParking.Simulation.Commands;
|
||||
|
||||
/// <summary>
|
||||
/// 自动发现带SimulationAction特性的测试方法并分发网页命令。
|
||||
/// </summary>
|
||||
public sealed class SimulationCommandDispatcher
|
||||
{
|
||||
private readonly SimulationWorld _world;
|
||||
private readonly IReadOnlyDictionary<string, RegisteredAction> _actions;
|
||||
|
||||
public SimulationCommandDispatcher(
|
||||
SimulationWorld world)
|
||||
{
|
||||
_world = world;
|
||||
_actions = DiscoverActions();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 返回网页动态生成按钮所需的全部命令。
|
||||
/// </summary>
|
||||
public IReadOnlyList<SimulationActionDescriptor> GetActions()
|
||||
{
|
||||
return _actions.Values
|
||||
.Select(action => action.Descriptor)
|
||||
.OrderBy(action => action.Group)
|
||||
.ThenBy(action => action.Order)
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 对指定车辆执行一个已注册的测试方法。
|
||||
/// </summary>
|
||||
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<string, RegisteredAction>
|
||||
DiscoverActions()
|
||||
{
|
||||
var actions = new Dictionary<string, RegisteredAction>(
|
||||
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<SimulationActionAttribute>();
|
||||
|
||||
if (attribute == null)
|
||||
continue;
|
||||
|
||||
ValidateMethod(method, attribute);
|
||||
|
||||
var handler =
|
||||
(Func<SimulationVehicle, bool>)method.CreateDelegate(
|
||||
typeof(Func<SimulationVehicle, bool>));
|
||||
|
||||
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<SimulationVehicle, bool> Handler);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 网页测试命令的执行结果。
|
||||
/// </summary>
|
||||
public sealed record CommandResult(
|
||||
bool Success,
|
||||
string Message);
|
||||
Reference in New Issue
Block a user