Skip to content

Commit

Permalink
Added support for recursive complex data type (#1656)
Browse files Browse the repository at this point in the history
The Opc.Ua.Client.ComplexTypes package does not support recursive structs, i.e. a struct with a field that has the same data type as the struct.
An example of a recursive struct data type may look as follows:

PersonStructDataType
-  Name <String>
-  Age <Int32>
-  Children <PersonStructDataType[ ]>  (ValueRank == 1)
  • Loading branch information
htbmw committed Jan 11, 2022
1 parent 9188dcf commit b41fb36
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 2 deletions.
27 changes: 25 additions & 2 deletions Libraries/Opc.Ua.Client.ComplexTypes/ComplexTypeSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1066,7 +1066,8 @@ ExpandedNodeId xmlEncodingId
foreach (StructureField field in structureDefinition.Fields)
{
var newType = GetFieldType(field);
if (newType == null)
var isRecursiveDataType = IsRecursiveDataType(ExpandedNodeId.ToNodeId(complexTypeId, m_session.NamespaceUris), field.DataType);
if (newType == null && !isRecursiveDataType)
{
throw new DataTypeNotFoundException(field.DataType);
}
Expand All @@ -1085,13 +1086,35 @@ ExpandedNodeId xmlEncodingId
foreach (StructureField field in structureDefinition.Fields)
{
typeListEnumerator.MoveNext();
fieldBuilder.AddField(field, typeListEnumerator.Current, order);

// check for recursive data type:
// field has the same data type as the parent structure
var isRecursiveDataType = IsRecursiveDataType(ExpandedNodeId.ToNodeId(complexTypeId, m_session.NamespaceUris), field.DataType);
if (isRecursiveDataType)
{
if (field.ValueRank < 0) // scalar
{
fieldBuilder.AddField(field, (fieldBuilder as ComplexTypeFieldBuilder).StructureTypeBuilder, order);
}
else // array
{
var arrayType = (fieldBuilder as ComplexTypeFieldBuilder).StructureTypeBuilder.MakeArrayType();
fieldBuilder.AddField(field, arrayType, order);
}
}
else
{
fieldBuilder.AddField(field, typeListEnumerator.Current, order);
}
order++;
}

return fieldBuilder.CreateType();
}

private bool IsRecursiveDataType(NodeId structureDataType, NodeId fieldDataType)
=> fieldDataType.Equals(structureDataType);

/// <summary>
/// Determine the type of a field in a StructureField definition.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,10 @@ public Type CreateType()
}
#endregion Public Properties

#region Internal Properties
internal TypeBuilder StructureTypeBuilder { get => this.m_structureBuilder; }
#endregion

#region Private Member
private TypeBuilder m_structureBuilder;
private StructureType m_structureType;
Expand Down

0 comments on commit b41fb36

Please sign in to comment.