refactor(commons): consolidate List element-type/coercion into AttributeValueCodec; InstanceActor + CLI reuse it (#93)
This commit is contained in:
@@ -64,7 +64,13 @@ public static class AttributeValueCodec
|
||||
_ => el.GetRawText() // number/bool → "10" / "1.5" / "true"
|
||||
};
|
||||
|
||||
private static Type ElementClrType(DataType t) => t switch
|
||||
/// <summary>
|
||||
/// The CLR element type backing a <see cref="DataType.List"/> of the given
|
||||
/// element scalar — the single source of truth for the List element CLR
|
||||
/// mapping. Throws <see cref="FormatException"/> for an unsupported element
|
||||
/// type (see <see cref="IsValidElementType"/>).
|
||||
/// </summary>
|
||||
public static Type ElementClrType(DataType t) => t switch
|
||||
{
|
||||
DataType.String => typeof(string),
|
||||
DataType.Int32 => typeof(int),
|
||||
@@ -75,6 +81,49 @@ public static class AttributeValueCodec
|
||||
_ => throw new FormatException($"Unsupported list element type '{t}'.")
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Coerces a live CLR enumerable (e.g. an OPC UA array) into a typed
|
||||
/// <c>List<<see cref="ElementClrType"/>></c> for the given element type,
|
||||
/// converting each element with invariant culture (round-trip parse for
|
||||
/// DateTime). Strings are parsed; other CLR types are converted via
|
||||
/// <see cref="Convert"/>. This is the object-input counterpart to the
|
||||
/// string-input parsing in <see cref="Decode"/>: callers holding decoded JSON
|
||||
/// strings go through <see cref="Decode"/>; callers holding a runtime
|
||||
/// collection use this. Throws <see cref="FormatException"/> for an
|
||||
/// unsupported element type and may throw on an element that cannot be
|
||||
/// converted (the caller decides how to handle the failure).
|
||||
/// </summary>
|
||||
public static IList CoerceEnumerable(IEnumerable source, DataType elementType)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(source);
|
||||
var clrType = ElementClrType(elementType);
|
||||
var list = (IList)Activator.CreateInstance(typeof(List<>).MakeGenericType(clrType))!;
|
||||
foreach (var element in source)
|
||||
list.Add(CoerceElement(element, elementType));
|
||||
return list;
|
||||
}
|
||||
|
||||
private static object CoerceElement(object? element, DataType t)
|
||||
{
|
||||
if (element is null)
|
||||
throw new FormatException("List elements may not be null.");
|
||||
|
||||
var c = CultureInfo.InvariantCulture;
|
||||
return t switch
|
||||
{
|
||||
DataType.String => Convert.ToString(element, c)
|
||||
?? throw new FormatException("Null string element."),
|
||||
DataType.Int32 => element is string si ? int.Parse(si, c) : Convert.ToInt32(element, c),
|
||||
DataType.Float => element is string sf ? float.Parse(sf, c) : Convert.ToSingle(element, c),
|
||||
DataType.Double => element is string sd ? double.Parse(sd, c) : Convert.ToDouble(element, c),
|
||||
DataType.Boolean => element is string sb ? bool.Parse(sb) : Convert.ToBoolean(element, c),
|
||||
DataType.DateTime => element is string sdt
|
||||
? DateTime.Parse(sdt, c, DateTimeStyles.RoundtripKind)
|
||||
: Convert.ToDateTime(element, c),
|
||||
_ => throw new FormatException($"Unsupported list element type '{t}'.")
|
||||
};
|
||||
}
|
||||
|
||||
private static object? ParseScalar(string? s, DataType t)
|
||||
{
|
||||
if (s is null) throw new FormatException("List elements may not be null.");
|
||||
|
||||
Reference in New Issue
Block a user