using System;
namespace Aging.Infrastructure.Contracts
{
///
/// 资源键值对象,唯一标识一个可管理的硬件资源。
/// 格式: "DeviceId:Channel",如 "PSU024:CH1"、"CAN_CARD01:CH2"、"PLC01:OUTPUT_GROUP_A"
///
public sealed class ResourceKey : IEquatable
{
///
/// 设备标识符
///
public string DeviceId { get; }
///
/// 通道标识(可选)
///
public string? Channel { get; }
///
/// 资源类型(PowerSupply/CAN/PLC/Chamber等)
///
public string ResourceType { get; }
///
/// 初始化资源键实例
///
/// 设备标识符
/// 资源类型
/// 通道标识(可选)
public ResourceKey(string deviceId, string resourceType, string? channel = null)
{
DeviceId = deviceId ?? throw new ArgumentNullException(nameof(deviceId));
ResourceType = resourceType ?? throw new ArgumentNullException(nameof(resourceType));
Channel = channel;
}
///
/// 从字符串解析资源键,格式为 "DeviceId:Channel"
///
/// 资源键字符串
/// 解析后的资源键实例
/// 格式无效时抛出
public static ResourceKey FromString(string key)
{
if (string.IsNullOrWhiteSpace(key))
throw new ArgumentException("资源键不能为空", nameof(key));
var parts = key.Split(':');
if (parts.Length < 2)
throw new ArgumentException($"无效的资源键格式: '{key}',期望格式为 'DeviceId:Channel'");
var deviceId = parts[0].Trim();
var channel = string.Join(":", parts.Skip(1)).Trim();
if (string.IsNullOrEmpty(deviceId))
throw new ArgumentException($"无效的资源键格式: '{key}',DeviceId 不能为空");
// 根据设备ID前缀推断资源类型
var resourceType = InferResourceType(deviceId);
return new ResourceKey(deviceId, resourceType, string.IsNullOrEmpty(channel) ? null : channel);
}
///
/// 获取操作资源键,用于物理会话锁
///
public string OperationResourceKey => $"{DeviceId}:SESSION";
///
/// 根据设备ID前缀推断资源类型
///
private static string InferResourceType(string deviceId)
{
var upper = deviceId.ToUpperInvariant();
if (upper.StartsWith("PSU") || upper.StartsWith("POWER"))
return "PowerSupply";
if (upper.StartsWith("CAN"))
return "CAN";
if (upper.StartsWith("PLC"))
return "PLC";
if (upper.StartsWith("CHAMBER") || upper.StartsWith("TEMP"))
return "Chamber";
if (upper.StartsWith("DAQ"))
return "DAQ";
if (upper.StartsWith("SERIAL") || upper.StartsWith("COM"))
return "Serial";
return "Generic";
}
///
public bool Equals(ResourceKey? other)
{
if (other is null) return false;
if (ReferenceEquals(this, other)) return true;
return string.Equals(DeviceId, other.DeviceId, StringComparison.OrdinalIgnoreCase) &&
string.Equals(Channel, other.Channel, StringComparison.OrdinalIgnoreCase) &&
string.Equals(ResourceType, other.ResourceType, StringComparison.OrdinalIgnoreCase);
}
///
public override bool Equals(object? obj) => Equals(obj as ResourceKey);
///
public override int GetHashCode()
{
unchecked
{
int hash = 17;
hash = hash * 31 + (DeviceId?.ToUpperInvariant().GetHashCode() ?? 0);
hash = hash * 31 + (Channel?.ToUpperInvariant().GetHashCode() ?? 0);
hash = hash * 31 + (ResourceType?.ToUpperInvariant().GetHashCode() ?? 0);
return hash;
}
}
///
public override string ToString() =>
string.IsNullOrEmpty(Channel) ? DeviceId : $"{DeviceId}:{Channel}";
///
/// 相等运算符重载
///
public static bool operator ==(ResourceKey? left, ResourceKey? right) =>
Equals(left, right);
///
/// 不等运算符重载
///
public static bool operator !=(ResourceKey? left, ResourceKey? right) =>
!Equals(left, right);
}
}