Files
lmxopcua/src/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer/SdkValueBoundary.cs
T
2026-11-10 10:20:53 -05:00

41 lines
1.9 KiB
C#

using Opc.Ua;
namespace ZB.MOM.WW.OtOpcUa.OpcUaServer;
/// <summary>Copies supported SDK payloads at the server's CLR value boundary.</summary>
internal static class SdkValueBoundary
{
/// <summary>Build a detached Variant for an existing supported scalar or one-dimensional array.</summary>
internal static Variant FromClr(object? value, bool byteArray = false)
{
if (value is null) return Variant.Null;
if (value is Array array)
{
if (array.Rank != 1) throw new ArgumentException("Only one-dimensional values are supported.", nameof(value));
value = array.Clone();
}
if (value is byte[] bytes) return byteArray
? Variant.From((ArrayOf<byte>)bytes)
: Variant.From(ByteString.From(bytes));
if (VariantHelper.TryCastFrom(value, out var variant)) return variant;
throw new ArgumentException("Unsupported OPC UA value type.", nameof(value));
}
/// <summary>Map the UA zero timestamp to the application's existing unspecified-bound sentinel.</summary>
internal static DateTime ToClrTimestamp(DateTimeUtc value) => value == DateTimeUtc.MinValue
? DateTime.SpecifyKind(DateTime.MinValue, DateTimeKind.Utc) : value.ToDateTime();
/// <summary>Restore existing CLR payload types and detach mutable arrays.</summary>
internal static object? ToClr(Variant value) => value.AsBoxedObject(Variant.BoxingBehavior.Legacy) switch
{
ByteString bytes => bytes.IsNull ? null : bytes.ToArray(),
DateTimeUtc time => time.ToDateTime(),
Uuid id => (Guid)id,
DateTimeUtc[] times => times.Select(x => x.ToDateTime()).ToArray(),
Uuid[] ids => ids.Select(x => (Guid)x).ToArray(),
ByteString[] strings => strings.Select(x => x.IsNull ? null : x.ToArray()).ToArray(),
Array array => array.Clone(),
var scalar => scalar,
};
}