/// <summary> /// Add an enum type defined in a binary schema dictionary. /// </summary> private void AddEnumTypes( IComplexTypeBuilder complexTypeBuilder, IList <Opc.Ua.Schema.Binary.TypeDescription> enumList, IList <INode> enumerationTypes ) { foreach (var item in enumList) { Type newType = null; DataTypeNode enumType = enumerationTypes.Where(node => node.BrowseName.Name == item.Name && (node.NodeId.NamespaceIndex == complexTypeBuilder.TargetNamespaceIndex || complexTypeBuilder.TargetNamespaceIndex == -1)).FirstOrDefault() as DataTypeNode; if (enumType != null) { // try dictionary enum definition var enumeratedObject = item as Schema.Binary.EnumeratedType; if (enumeratedObject != null) { // 1. use Dictionary entry newType = complexTypeBuilder.AddEnumType(enumeratedObject); } if (newType == null) { var dataType = m_session.NodeCache.Find(enumType.NodeId) as DataTypeNode; if (dataType != null) { if (dataType.DataTypeDefinition != null) { // 2. use DataTypeDefinition newType = complexTypeBuilder.AddEnumType(enumType.BrowseName.Name, dataType.DataTypeDefinition); } else { // browse for EnumFields or EnumStrings property var property = BrowseForSingleProperty(enumType.NodeId); var enumArray = m_session.ReadValue( ExpandedNodeId.ToNodeId(property.NodeId, m_session.NamespaceUris)); if (enumArray.Value is ExtensionObject[]) { // 3. use EnumValues newType = complexTypeBuilder.AddEnumType(enumType.BrowseName.Name, (ExtensionObject[])enumArray.Value); } else if (enumArray.Value is LocalizedText[]) { // 4. use EnumStrings newType = complexTypeBuilder.AddEnumType(enumType.BrowseName.Name, (LocalizedText[])enumArray.Value); } } } } if (newType != null) { // match namespace and add to type factory AddEncodeableType(enumType.NodeId, newType); } } } }
/// <summary> /// Return the structure definition from a DataTypeDefinition /// </summary> private StructureDefinition GetStructureDefinition(DataTypeNode dataTypeNode) { if (dataTypeNode.DataTypeDefinition?.Body is StructureDefinition structureDefinition) { return(structureDefinition); } return(null); }
/// <summary> /// Add an enum type defined in a DataType node. /// </summary> private Type AddEnumType( IComplexTypeBuilder complexTypeBuilder, DataTypeNode enumTypeNode ) { Type newType = null; if (enumTypeNode != null) { string name = enumTypeNode.BrowseName.Name; if (enumTypeNode.DataTypeDefinition != null) { // 1. use DataTypeDefinition newType = complexTypeBuilder.AddEnumType(name, enumTypeNode.DataTypeDefinition); } else { // browse for EnumFields or EnumStrings property var property = BrowseForSingleProperty(enumTypeNode.NodeId); if (property != null) { var enumArray = m_session.ReadValue( ExpandedNodeId.ToNodeId(property.NodeId, m_session.NamespaceUris)); if (enumArray.Value is ExtensionObject[]) { // 2. use EnumValues newType = complexTypeBuilder.AddEnumType(name, (ExtensionObject[])enumArray.Value); } else if (enumArray.Value is LocalizedText[]) { // 3. use EnumStrings newType = complexTypeBuilder.AddEnumType(name, (LocalizedText[])enumArray.Value); } } } } return(newType); }
/// <summary> /// Browse for the type and encoding id for a dictionary component. /// </summary> /// <remarks> /// According to Part 5 Annex D, servers shall provide the bi-directional /// references between data types, data type encodings, data type description /// and data type dictionary. /// To find the typeId and encodingId for a dictionary type definition: /// i) inverse browse the description to get the encodingid /// ii) from the description inverse browse for encoding /// to get the subtype typeid /// iii) load the DataType node /// </remarks> /// <param name="nodeId"></param> /// <param name="typeId"></param> /// <param name="encodingId"></param> /// <returns>true if successful, false otherwise</returns> private bool BrowseTypeIdsForDictionaryComponent( NodeId nodeId, out ExpandedNodeId typeId, out ExpandedNodeId encodingId, out DataTypeNode dataTypeNode) { typeId = ExpandedNodeId.Null; encodingId = ExpandedNodeId.Null; dataTypeNode = null; var references = m_session.NodeCache.FindReferences( nodeId, ReferenceTypeIds.HasDescription, true, false ); if (references.Count == 1) { encodingId = references[0].NodeId; references = m_session.NodeCache.FindReferences( encodingId, ReferenceTypeIds.HasEncoding, true, false ); encodingId = NormalizeExpandedNodeId(encodingId); if (references.Count == 1) { typeId = references[0].NodeId; dataTypeNode = m_session.NodeCache.Find(typeId) as DataTypeNode; typeId = NormalizeExpandedNodeId(typeId); return true; } } return false; }
public AbstractDataType(DataTypeNode node) { Node = node; Name = node.Name; }
public Node ReadNode(NodeId nodeId) { // build list of attributes. SortedDictionary<uint,DataValue> attributes = new SortedDictionary<uint,DataValue>(); attributes.Add(Attributes.NodeId, null); attributes.Add(Attributes.NodeClass, null); attributes.Add(Attributes.BrowseName, null); attributes.Add(Attributes.DisplayName, null); attributes.Add(Attributes.Description, null); attributes.Add(Attributes.WriteMask, null); attributes.Add(Attributes.UserWriteMask, null); attributes.Add(Attributes.DataType, null); attributes.Add(Attributes.ValueRank, null); attributes.Add(Attributes.ArrayDimensions, null); attributes.Add(Attributes.AccessLevel, null); attributes.Add(Attributes.UserAccessLevel, null); attributes.Add(Attributes.Historizing, null); attributes.Add(Attributes.MinimumSamplingInterval, null); attributes.Add(Attributes.EventNotifier, null); attributes.Add(Attributes.Executable, null); attributes.Add(Attributes.UserExecutable, null); attributes.Add(Attributes.IsAbstract, null); attributes.Add(Attributes.InverseName, null); attributes.Add(Attributes.Symmetric, null); attributes.Add(Attributes.ContainsNoLoops, null); // build list of values to read. ReadValueIdCollection itemsToRead = new ReadValueIdCollection(); foreach (uint attributeId in attributes.Keys) { ReadValueId itemToRead = new ReadValueId(); itemToRead.NodeId = nodeId; itemToRead.AttributeId = attributeId; itemsToRead.Add(itemToRead); } // read from server. DataValueCollection values = null; DiagnosticInfoCollection diagnosticInfos = null; ResponseHeader responseHeader = Read( null, 0, TimestampsToReturn.Neither, itemsToRead, out values, out diagnosticInfos); ClientBase.ValidateResponse(values, itemsToRead); ClientBase.ValidateDiagnosticInfos(diagnosticInfos, itemsToRead); // process results. int? nodeClass = null; for (int ii = 0; ii < itemsToRead.Count; ii++) { uint attributeId = itemsToRead[ii].AttributeId; // the node probably does not exist if the node class is not found. if (attributeId == Attributes.NodeClass) { if (!DataValue.IsGood(values[ii])) { throw ServiceResultException.Create(values[ii].StatusCode, ii, diagnosticInfos, responseHeader.StringTable); } // check for valid node class. nodeClass = values[ii].Value as int?; if (nodeClass == null) { throw ServiceResultException.Create(StatusCodes.BadUnexpectedError, "Node does not have a valid value for NodeClass: {0}.", values[ii].Value); } } else { if (!DataValue.IsGood(values[ii])) { // check for unsupported attributes. if (values[ii].StatusCode == StatusCodes.BadAttributeIdInvalid) { continue; } // all supported attributes must be readable. if (attributeId != Attributes.Value) { throw ServiceResultException.Create(values[ii].StatusCode, ii, diagnosticInfos, responseHeader.StringTable); } } } attributes[attributeId] = values[ii]; } Node node = null; DataValue value = null; switch ((NodeClass)nodeClass.Value) { default: { throw ServiceResultException.Create(StatusCodes.BadUnexpectedError, "Node does not have a valid value for NodeClass: {0}.", nodeClass.Value); } case NodeClass.Object: { ObjectNode objectNode = new ObjectNode(); value = attributes[Attributes.EventNotifier]; if (value == null) { throw ServiceResultException.Create(StatusCodes.BadUnexpectedError, "Object does not support the EventNotifier attribute."); } objectNode.EventNotifier = (byte)attributes[Attributes.EventNotifier].GetValue(typeof(byte)); node = objectNode; break; } case NodeClass.ObjectType: { ObjectTypeNode objectTypeNode = new ObjectTypeNode(); value = attributes[Attributes.IsAbstract]; if (value == null) { throw ServiceResultException.Create(StatusCodes.BadUnexpectedError, "ObjectType does not support the IsAbstract attribute."); } objectTypeNode.IsAbstract = (bool)attributes[Attributes.IsAbstract].GetValue(typeof(bool)); node = objectTypeNode; break; } case NodeClass.Variable: { VariableNode variableNode = new VariableNode(); // DataType Attribute value = attributes[Attributes.DataType]; if (value == null) { throw ServiceResultException.Create(StatusCodes.BadUnexpectedError, "Variable does not support the DataType attribute."); } variableNode.DataType = (NodeId)attributes[Attributes.DataType].GetValue(typeof(NodeId)); // ValueRank Attribute value = attributes[Attributes.ValueRank]; if (value == null) { throw ServiceResultException.Create(StatusCodes.BadUnexpectedError, "Variable does not support the ValueRank attribute."); } variableNode.ValueRank = (int)attributes[Attributes.ValueRank].GetValue(typeof(int)); // ArrayDimensions Attribute value = attributes[Attributes.ArrayDimensions]; if (value != null) { if (value.Value == null) { variableNode.ArrayDimensions = new uint[0]; } else { variableNode.ArrayDimensions = (uint[])value.GetValue(typeof(uint[])); } } // AccessLevel Attribute value = attributes[Attributes.AccessLevel]; if (value == null) { throw ServiceResultException.Create(StatusCodes.BadUnexpectedError, "Variable does not support the AccessLevel attribute."); } variableNode.AccessLevel = (byte)attributes[Attributes.AccessLevel].GetValue(typeof(byte)); // UserAccessLevel Attribute value = attributes[Attributes.UserAccessLevel]; if (value == null) { throw ServiceResultException.Create(StatusCodes.BadUnexpectedError, "Variable does not support the UserAccessLevel attribute."); } variableNode.UserAccessLevel = (byte)attributes[Attributes.UserAccessLevel].GetValue(typeof(byte)); // Historizing Attribute value = attributes[Attributes.Historizing]; if (value == null) { throw ServiceResultException.Create(StatusCodes.BadUnexpectedError, "Variable does not support the Historizing attribute."); } variableNode.Historizing = (bool)attributes[Attributes.Historizing].GetValue(typeof(bool)); // MinimumSamplingInterval Attribute value = attributes[Attributes.MinimumSamplingInterval]; if (value != null) { variableNode.MinimumSamplingInterval = Convert.ToDouble(attributes[Attributes.MinimumSamplingInterval].Value); } node = variableNode; break; } case NodeClass.VariableType: { VariableTypeNode variableTypeNode = new VariableTypeNode(); // IsAbstract Attribute value = attributes[Attributes.IsAbstract]; if (value == null) { throw ServiceResultException.Create(StatusCodes.BadUnexpectedError, "VariableType does not support the IsAbstract attribute."); } variableTypeNode.IsAbstract = (bool)attributes[Attributes.IsAbstract].GetValue(typeof(bool)); // DataType Attribute value = attributes[Attributes.DataType]; if (value == null) { throw ServiceResultException.Create(StatusCodes.BadUnexpectedError, "VariableType does not support the DataType attribute."); } variableTypeNode.DataType = (NodeId)attributes[Attributes.DataType].GetValue(typeof(NodeId)); // ValueRank Attribute value = attributes[Attributes.ValueRank]; if (value == null) { throw ServiceResultException.Create(StatusCodes.BadUnexpectedError, "VariableType does not support the ValueRank attribute."); } variableTypeNode.ValueRank = (int)attributes[Attributes.ValueRank].GetValue(typeof(int)); // ArrayDimensions Attribute value = attributes[Attributes.ArrayDimensions]; if (value != null && value.Value != null) { variableTypeNode.ArrayDimensions = (uint[])attributes[Attributes.ArrayDimensions].GetValue(typeof(uint[])); } node = variableTypeNode; break; } case NodeClass.Method: { MethodNode methodNode = new MethodNode(); // Executable Attribute value = attributes[Attributes.Executable]; if (value == null) { throw ServiceResultException.Create(StatusCodes.BadUnexpectedError, "Method does not support the Executable attribute."); } methodNode.Executable = (bool)attributes[Attributes.Executable].GetValue(typeof(bool)); // UserExecutable Attribute value = attributes[Attributes.UserExecutable]; if (value == null) { throw ServiceResultException.Create(StatusCodes.BadUnexpectedError, "Method does not support the UserExecutable attribute."); } methodNode.UserExecutable = (bool)attributes[Attributes.UserExecutable].GetValue(typeof(bool)); node = methodNode; break; } case NodeClass.DataType: { DataTypeNode dataTypeNode = new DataTypeNode(); // IsAbstract Attribute value = attributes[Attributes.IsAbstract]; if (value == null) { throw ServiceResultException.Create(StatusCodes.BadUnexpectedError, "DataType does not support the IsAbstract attribute."); } dataTypeNode.IsAbstract = (bool)attributes[Attributes.IsAbstract].GetValue(typeof(bool)); node = dataTypeNode; break; } case NodeClass.ReferenceType: { ReferenceTypeNode referenceTypeNode = new ReferenceTypeNode(); // IsAbstract Attribute value = attributes[Attributes.IsAbstract]; if (value == null) { throw ServiceResultException.Create(StatusCodes.BadUnexpectedError, "ReferenceType does not support the IsAbstract attribute."); } referenceTypeNode.IsAbstract = (bool)attributes[Attributes.IsAbstract].GetValue(typeof(bool)); // Symmetric Attribute value = attributes[Attributes.Symmetric]; if (value == null) { throw ServiceResultException.Create(StatusCodes.BadUnexpectedError, "ReferenceType does not support the Symmetric attribute."); } referenceTypeNode.Symmetric = (bool)attributes[Attributes.IsAbstract].GetValue(typeof(bool)); // InverseName Attribute value = attributes[Attributes.InverseName]; if (value != null && value.Value != null) { referenceTypeNode.InverseName = (LocalizedText)attributes[Attributes.InverseName].GetValue(typeof(LocalizedText)); } node = referenceTypeNode; break; } case NodeClass.View: { ViewNode viewNode = new ViewNode(); // EventNotifier Attribute value = attributes[Attributes.EventNotifier]; if (value == null) { throw ServiceResultException.Create(StatusCodes.BadUnexpectedError, "View does not support the EventNotifier attribute."); } viewNode.EventNotifier = (byte)attributes[Attributes.EventNotifier].GetValue(typeof(byte)); // ContainsNoLoops Attribute value = attributes[Attributes.ContainsNoLoops]; if (value == null) { throw ServiceResultException.Create(StatusCodes.BadUnexpectedError, "View does not support the ContainsNoLoops attribute."); } viewNode.ContainsNoLoops = (bool)attributes[Attributes.ContainsNoLoops].GetValue(typeof(bool)); node = viewNode; break; } } // NodeId Attribute value = attributes[Attributes.NodeId]; if (value == null) { throw ServiceResultException.Create(StatusCodes.BadUnexpectedError, "Node does not support the NodeId attribute."); } node.NodeId = (NodeId)attributes[Attributes.NodeId].GetValue(typeof(NodeId)); node.NodeClass = (NodeClass)nodeClass.Value; // BrowseName Attribute value = attributes[Attributes.BrowseName]; if (value == null) { throw ServiceResultException.Create(StatusCodes.BadUnexpectedError, "Node does not support the BrowseName attribute."); } node.BrowseName = (QualifiedName)attributes[Attributes.BrowseName].GetValue(typeof(QualifiedName)); // DisplayName Attribute value = attributes[Attributes.DisplayName]; if (value == null) { throw ServiceResultException.Create(StatusCodes.BadUnexpectedError, "Node does not support the DisplayName attribute."); } node.DisplayName = (LocalizedText)attributes[Attributes.DisplayName].GetValue(typeof(LocalizedText)); // Description Attribute value = attributes[Attributes.Description]; if (value != null && value.Value != null) { node.Description = (LocalizedText)attributes[Attributes.Description].GetValue(typeof(LocalizedText)); } // WriteMask Attribute value = attributes[Attributes.WriteMask]; if (value != null) { node.WriteMask = (uint)attributes[Attributes.WriteMask].GetValue(typeof(uint)); } // UserWriteMask Attribute value = attributes[Attributes.UserWriteMask]; if (value != null) { node.WriteMask = (uint)attributes[Attributes.UserWriteMask].GetValue(typeof(uint)); } return node; }
/// <summary> /// Creates an DataType node in the address space. /// </summary> public NodeId CreateDataType( NodeId parentId, NodeId nodeId, QualifiedName browseName, LocalizedText displayName, LocalizedText description, uint writeMask, uint userWriteMask, bool isAbstract, IDictionary<QualifiedName,NodeId> encodings) { if (parentId == null) throw new ArgumentNullException("parentId"); if (browseName == null) throw new ArgumentNullException("browseName"); try { m_lock.Enter(); // check for null node id. if (NodeId.IsNull(nodeId)) { nodeId = CreateUniqueNodeId(); } // check if node id exists. if (m_nodes.Exists(nodeId)) { throw ServiceResultException.Create(StatusCodes.BadNodeIdExists, "NodeId '{0}' already exists.", nodeId); } // find parent. IDataType parent = GetManagerHandle(parentId) as IDataType; if (parent == null) { throw ServiceResultException.Create(StatusCodes.BadParentNodeIdInvalid, "Parent node '{0}' does not exist or is not an DataTypeNode.", parentId); } // validate reference. ValidateReference(parent, ReferenceTypeIds.HasSubtype, false, NodeClass.DataType); // validate browse name. if (QualifiedName.IsNull(browseName)) { throw ServiceResultException.Create(StatusCodes.BadBrowseNameInvalid, "BrowsName must not be empty."); } // create node. DataTypeNode node = new DataTypeNode(); node.NodeId = nodeId; node.NodeClass = NodeClass.DataType; node.BrowseName = browseName; node.DisplayName = displayName; node.WriteMask = writeMask; node.UserWriteMask = userWriteMask; node.Description = description; node.IsAbstract = isAbstract; // add reference from parent. AddReference(parent, ReferenceTypeIds.HasSubtype, false, node, true); // add node. AddNode(node); // add the encodings. if (encodings != null) { List<QualifiedName> encodingNames = new List<QualifiedName>(encodings.Keys); foreach (QualifiedName encodingName in encodingNames) { // assign a unique id to the encoding if none provided. NodeId encodingId = encodings[encodingName]; if (NodeId.IsNull(encodingId)) { encodingId = CreateUniqueNodeId(); } ObjectAttributes attributes = new ObjectAttributes(); attributes.SpecifiedAttributes = (uint)NodeAttributesMask.None; // return the actual id. encodings[encodingName] = CreateObject( nodeId, ReferenceTypeIds.HasEncoding, encodingId, encodingName, attributes, ObjectTypes.DataTypeEncodingType); } } // return the new node id. return node.NodeId; } finally { m_lock.Exit(); } }
/// <summary> /// Returns the value of an attribute. /// </summary> public void Read( ReadValueId request, DataValue result, DiagnosticInfo diagnosticInfo) { lock (m_lock) { // find the node to read. Node source = m_nodes.Find(request.NodeId); result.ServerTimestamp = DateTime.UtcNow; if (source == null) { result.StatusCode = new StatusCode(StatusCodes.BadNodeIdUnknown); return; } result.Value = Variant.Null; // switch on the attribute value. switch (request.AttributeId) { case Attributes.NodeId: { result.Value = new Variant(source.NodeId); break; } case Attributes.NodeClass: { result.Value = new Variant(DataTypes.EnumToMask(source.NodeClass)); break; } case Attributes.BrowseName: { result.Value = new Variant(source.BrowseName); break; } case Attributes.DisplayName: { result.Value = new Variant(source.DisplayName); break; } case Attributes.Description: { result.Value = new Variant(source.Description); break; } case Attributes.WriteMask: { result.Value = new Variant(source.WriteMask); break; } case Attributes.UserWriteMask: { result.Value = new Variant(source.UserWriteMask); break; } case Attributes.Value: { // check if another component has installed a read callback. ReadValueEventHandler callback = null; if (m_callbacks.TryGetValue(source.NodeId.Identifier, out callback)) { result.Value = new Variant(callback()); break; } // use the value cached in the node otherwise. VariableNode variable = source as VariableNode; if (variable != null) { result.Value = variable.Value; result.SourceTimestamp = DateTime.UtcNow; // The Value attribute requires a SourceTimestamp. break; } VariableTypeNode variableType = source as VariableTypeNode; if (variableType != null) { result.Value = variableType.Value; result.SourceTimestamp = DateTime.UtcNow; // The Value attribute requires a SourceTimestamp. break; } result.StatusCode = new StatusCode(StatusCodes.BadAttributeIdInvalid); break; } case Attributes.DataType: { VariableNode variable = source as VariableNode; if (variable != null) { result.Value = new Variant(variable.DataType); break; } VariableTypeNode variableType = source as VariableTypeNode; if (variableType != null) { result.Value = new Variant(variableType.DataType); break; } result.StatusCode = new StatusCode(StatusCodes.BadAttributeIdInvalid); break; } case Attributes.ValueRank: { VariableNode variable = source as VariableNode; if (variable != null) { result.Value = new Variant(variable.ValueRank); break; } VariableTypeNode variableType = source as VariableTypeNode; if (variableType != null) { result.Value = new Variant(variableType.ValueRank); break; } result.StatusCode = new StatusCode(StatusCodes.BadAttributeIdInvalid); break; } case Attributes.MinimumSamplingInterval: { VariableNode variable = source as VariableNode; if (variable != null) { result.Value = new Variant(variable.MinimumSamplingInterval); break; } result.StatusCode = new StatusCode(StatusCodes.BadAttributeIdInvalid); break; } case Attributes.Historizing: { VariableNode variable = source as VariableNode; if (variable != null) { result.Value = new Variant(variable.Historizing); break; } result.StatusCode = new StatusCode(StatusCodes.BadAttributeIdInvalid); break; } case Attributes.AccessLevel: { VariableNode variable = source as VariableNode; if (variable != null) { result.Value = new Variant(variable.AccessLevel); break; } result.StatusCode = new StatusCode(StatusCodes.BadAttributeIdInvalid); break; } case Attributes.UserAccessLevel: { VariableNode variable = source as VariableNode; if (variable != null) { result.Value = new Variant(variable.UserAccessLevel); break; } result.StatusCode = new StatusCode(StatusCodes.BadAttributeIdInvalid); break; } case Attributes.EventNotifier: { ObjectNode objectn = source as ObjectNode; if (objectn != null) { result.Value = new Variant(objectn.EventNotifier); break; } ViewNode view = source as ViewNode; if (view != null) { result.Value = new Variant(view.EventNotifier); break; } result.StatusCode = new StatusCode(StatusCodes.BadAttributeIdInvalid); break; } case Attributes.Executable: { MethodNode method = source as MethodNode; if (method != null) { result.Value = new Variant(method.Executable); break; } result.StatusCode = new StatusCode(StatusCodes.BadAttributeIdInvalid); break; } case Attributes.UserExecutable: { MethodNode method = source as MethodNode; if (method != null) { result.Value = new Variant(method.UserExecutable); break; } result.StatusCode = new StatusCode(StatusCodes.BadAttributeIdInvalid); break; } case Attributes.ContainsNoLoops: { ViewNode view = source as ViewNode; if (view != null) { result.Value = new Variant(view.ContainsNoLoops); break; } result.StatusCode = new StatusCode(StatusCodes.BadAttributeIdInvalid); break; } case Attributes.InverseName: { ReferenceTypeNode referenceType = source as ReferenceTypeNode; if (referenceType != null) { result.Value = new Variant(referenceType.InverseName); break; } result.StatusCode = new StatusCode(StatusCodes.BadAttributeIdInvalid); break; } case Attributes.IsAbstract: { DataTypeNode dataType = source as DataTypeNode; if (dataType != null) { result.Value = new Variant(dataType.IsAbstract); break; } ReferenceTypeNode referenceType = source as ReferenceTypeNode; if (referenceType != null) { result.Value = new Variant(referenceType.IsAbstract); break; } ObjectTypeNode objectType = source as ObjectTypeNode; if (objectType != null) { result.Value = new Variant(objectType.IsAbstract); break; } VariableTypeNode variableType = source as VariableTypeNode; if (variableType != null) { result.Value = new Variant(variableType.IsAbstract); break; } result.StatusCode = new StatusCode(StatusCodes.BadAttributeIdInvalid); break; } case Attributes.Symmetric: { ReferenceTypeNode referenceType = source as ReferenceTypeNode; if (referenceType != null) { result.Value = new Variant(referenceType.Symmetric); break; } result.StatusCode = new StatusCode(StatusCodes.BadAttributeIdInvalid); break; } default: { result.StatusCode = new StatusCode(StatusCodes.BadAttributeIdInvalid); break; } } } }