mirror of
https://github.com/OPCFoundation/UA-.NETStandard.git
synced 2026-10-28 22:55:49 +08:00
Enhance enum definition handling and validation (#3124)
* Enhance enum definition handling and validation Added a `string enumTypeName` parameter to the `ToEnumDefinition` methods in `ComplexTypeSystem.cs` and `DataTypeDefinitionExtension.cs` to improve enum field name generation, especially when original names are null or empty. Implemented a fallback mechanism to ensure robust naming. In `ComplexTypeBuilder.cs`, added null checks for `typeName` to prevent runtime errors and ensure valid type definitions. Updated logic for defining enum literals to handle empty field names, ensuring unique names are generated based on `typeName` and enum value. * Update Libraries/Opc.Ua.Client.ComplexTypes/TypeBuilder/ComplexTypeBuilder.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update Libraries/Opc.Ua.Client.ComplexTypes/DataTypeDefinitionExtension.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Fix issue from code review --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -899,7 +899,7 @@ namespace Opc.Ua.Client.ComplexTypes
|
||||
if (item is Schema.Binary.EnumeratedType enumeratedObject)
|
||||
{
|
||||
// 1. use Dictionary entry
|
||||
var enumDefinition = enumeratedObject.ToEnumDefinition();
|
||||
var enumDefinition = enumeratedObject.ToEnumDefinition(enumeratedObject.Name);
|
||||
|
||||
// Add EnumDefinition to cache
|
||||
m_dataTypeDefinitionCache[enumType.NodeId] = enumDefinition;
|
||||
@@ -971,12 +971,12 @@ namespace Opc.Ua.Client.ComplexTypes
|
||||
if (enumTypeArray is ExtensionObject[] extensionObject)
|
||||
{
|
||||
// 2. use EnumValues
|
||||
enumDefinition = extensionObject.ToEnumDefinition();
|
||||
enumDefinition = extensionObject.ToEnumDefinition(name.Name);
|
||||
}
|
||||
else if (enumTypeArray is LocalizedText[] localizedText)
|
||||
{
|
||||
// 3. use EnumStrings
|
||||
enumDefinition = localizedText.ToEnumDefinition();
|
||||
enumDefinition = localizedText.ToEnumDefinition(name.Name);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -237,20 +237,33 @@ namespace Opc.Ua.Client.ComplexTypes
|
||||
/// Convert a binary schema enumerated type to an enum data type definition
|
||||
/// Available before OPC UA V1.04.
|
||||
/// </summary>
|
||||
public static EnumDefinition ToEnumDefinition(this Schema.Binary.EnumeratedType enumeratedType)
|
||||
public static EnumDefinition ToEnumDefinition(this Schema.Binary.EnumeratedType enumeratedType, string enumTypeName)
|
||||
{
|
||||
var enumDefinition = new EnumDefinition();
|
||||
|
||||
foreach (var enumValue in enumeratedType.EnumeratedValue)
|
||||
if (enumeratedType.EnumeratedValue != null)
|
||||
{
|
||||
var enumTypeField = new EnumField
|
||||
foreach (var enumValue in enumeratedType.EnumeratedValue)
|
||||
{
|
||||
Name = enumValue.Name,
|
||||
Value = enumValue.Value,
|
||||
Description = enumValue.Documentation?.Text?.FirstOrDefault(),
|
||||
DisplayName = enumValue.Name
|
||||
};
|
||||
enumDefinition.Fields.Add(enumTypeField);
|
||||
var fieldName = enumValue.Name;
|
||||
if (string.IsNullOrEmpty(fieldName))
|
||||
{
|
||||
if (string.IsNullOrEmpty(enumTypeName))
|
||||
{
|
||||
// Here we give up because the overall type is broken
|
||||
return null;
|
||||
}
|
||||
fieldName = $"{enumTypeName}_{enumValue.Value}";
|
||||
}
|
||||
|
||||
var enumTypeField = new EnumField {
|
||||
Name = fieldName,
|
||||
Value = enumValue.Value,
|
||||
Description = enumValue.Documentation?.Text?.FirstOrDefault(),
|
||||
DisplayName = enumValue.Name
|
||||
};
|
||||
enumDefinition.Fields.Add(enumTypeField);
|
||||
}
|
||||
}
|
||||
|
||||
return enumDefinition;
|
||||
@@ -260,14 +273,30 @@ namespace Opc.Ua.Client.ComplexTypes
|
||||
/// Convert a list of EnumValues to an enum data type definition
|
||||
/// Available before OPC UA V1.04.
|
||||
/// </summary>
|
||||
public static EnumDefinition ToEnumDefinition(this ExtensionObject[] enumValueTypes)
|
||||
public static EnumDefinition ToEnumDefinition(this ExtensionObject[] enumValueTypes, string enumTypeName)
|
||||
{
|
||||
var enumDefinition = new EnumDefinition();
|
||||
|
||||
foreach (var extensionObject in enumValueTypes)
|
||||
{
|
||||
var enumValue = extensionObject.Body as EnumValueType;
|
||||
if (extensionObject.Body is not EnumValueType enumValue)
|
||||
{
|
||||
// All we can do here is skip this value. Since there is no
|
||||
// fallback it is better to include all other type fields if
|
||||
// they are in the extension object array.
|
||||
continue;
|
||||
}
|
||||
|
||||
var name = enumValue.DisplayName.Text;
|
||||
if (string.IsNullOrEmpty(name))
|
||||
{
|
||||
if (string.IsNullOrEmpty(enumTypeName))
|
||||
{
|
||||
// Here we give up because the overall type is broken
|
||||
return null;
|
||||
}
|
||||
name = $"{enumTypeName}_{enumValue.Value}";
|
||||
}
|
||||
|
||||
var enumTypeField = new EnumField {
|
||||
Name = name,
|
||||
@@ -284,7 +313,7 @@ namespace Opc.Ua.Client.ComplexTypes
|
||||
/// Convert a list of EnumValues to an enum data type definition
|
||||
/// Available before OPC UA V1.04.
|
||||
/// </summary>
|
||||
public static EnumDefinition ToEnumDefinition(this LocalizedText[] enumFieldNames)
|
||||
public static EnumDefinition ToEnumDefinition(this LocalizedText[] enumFieldNames, string enumTypeName)
|
||||
{
|
||||
var enumDefinition = new EnumDefinition();
|
||||
|
||||
@@ -293,6 +322,16 @@ namespace Opc.Ua.Client.ComplexTypes
|
||||
LocalizedText enumFieldName = enumFieldNames[ii];
|
||||
var name = enumFieldName.Text;
|
||||
|
||||
if (string.IsNullOrEmpty(name))
|
||||
{
|
||||
if (string.IsNullOrEmpty(enumTypeName))
|
||||
{
|
||||
// Here we give up because the overall type is broken
|
||||
return null;
|
||||
}
|
||||
name = $"{enumTypeName}_{ii}";
|
||||
}
|
||||
|
||||
var enumTypeField = new EnumField {
|
||||
Name = name,
|
||||
Value = ii,
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
* ======================================================================*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Reflection.Emit;
|
||||
@@ -79,16 +80,42 @@ namespace Opc.Ua.Client.ComplexTypes
|
||||
{
|
||||
throw new ArgumentNullException(nameof(enumDefinition));
|
||||
}
|
||||
if (typeName == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(typeName));
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(typeName.Name))
|
||||
{
|
||||
// The type name should not be null or empty then the type definition
|
||||
// or xml is broken. For the latter we want to go into the fallback path
|
||||
// And try to read the data type definition's enum definition.
|
||||
return null;
|
||||
}
|
||||
|
||||
var enumBuilder = m_moduleBuilder.DefineEnum(
|
||||
GetFullQualifiedTypeName(typeName),
|
||||
TypeAttributes.Public,
|
||||
typeof(int));
|
||||
enumBuilder.DataContractAttribute(m_targetNamespace);
|
||||
foreach (var enumValue in enumDefinition.Fields)
|
||||
if (enumDefinition.Fields != null)
|
||||
{
|
||||
var newEnum = enumBuilder.DefineLiteral(enumValue.Name, (int)enumValue.Value);
|
||||
newEnum.EnumMemberAttribute(enumValue.Name, (int)enumValue.Value);
|
||||
var fieldNames = new HashSet<string>();
|
||||
foreach (EnumField enumValue in enumDefinition.Fields)
|
||||
{
|
||||
// Create a field from the type name and ensure it is not a duplicate
|
||||
var fieldName = enumValue.Name;
|
||||
if (string.IsNullOrEmpty(fieldName))
|
||||
{
|
||||
// This is to be super safe, but we should never get here.
|
||||
fieldName = $"{typeName.Name}_{enumValue.Value}";
|
||||
}
|
||||
if (fieldNames.Add(fieldName))
|
||||
{
|
||||
var newEnum = enumBuilder.DefineLiteral(fieldName, (int)enumValue.Value);
|
||||
newEnum.EnumMemberAttribute(fieldName, (int)enumValue.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
return enumBuilder.CreateTypeInfo();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user