QuickOPC User's Guide and Reference
DataTypeKind Enumeration
Example Example 



View with Navigation Tools
OpcLabs.BaseLib Assembly > OpcLabs.BaseLib.DataTypeModel Namespace : DataTypeKind Enumeration
The kind of a data type.
Syntax
'Declaration
 
<CLSCompliantAttribute(True)>
<ComVisibleAttribute(True)>
<DisplayName2Attribute("Data Type Kind")>
<GuidAttribute("5C1FFA82-46B6-4DC4-80A2-CD3D84929180")>
Public Enum DataTypeKind 
   Inherits System.Enum
   Implements System.IComparable, System.IConvertible, System.IFormattable 
 
'Usage
 
Dim instance As DataTypeKind
Members
MemberValueDescription
Enumeration4The data type is an enumeration.

Remarks:

Corresponds to the EnumerationDataType data type class and EnumerationData generic data class.

None0No data type kind.

Remarks:

This value isn't actually used.

Opaque3The data type is opaque.

Remarks:

Corresponds to the OpaqueDataType data type class and OpaqueData generic data class.

Primitive1The data type is primitive.

Remarks:

Corresponds to the PrimitiveDataType data type class and PrimitiveData generic data class.

Sequence2The data type is a sequence.

Remarks:

Corresponds to the SequenceDataType data type class and SequenceData generic data class.

Structured5The data type is structured.

Remarks:

Corresponds to the StructuredDataType data type class and StructuredData generic data class.

Union6The data type is a union.
Remarks

The data type kinds correspond to classes derived from DataType. The following picture shows the class hierarchy:

.

Example

.NET

COM

.NET

COM

// Shows how to process a data type, displaying some of its properties, recursively.

using System;
using System.Linq;
using OpcLabs.BaseLib.DataTypeModel;
using OpcLabs.EasyOpc.UA;
using OpcLabs.EasyOpc.UA.ComplexData;
using OpcLabs.EasyOpc.UA.OperationModel;

namespace UADocExamples.ComplexData._DataType
{
    class Kind
    {
        public static void Main1()
        {
            // Define which server and node we will work with.
            UAEndpointDescriptor endpointDescriptor =
                "opc.tcp://opcua.demo-this.com:51210/UA/SampleServer";
            // or "http://opcua.demo-this.com:51211/UA/SampleServer" (currently not supported)
            // or "https://opcua.demo-this.com:51212/UA/SampleServer/"
            UANodeDescriptor nodeDescriptor = 
                "nsu=http://test.org/UA/Data/ ;i=10239"; // [ObjectsFolder]/Data.Static.Scalar.StructureValue

            // Instantiate the client object.
            var client = new EasyUAClient();

            // Read a node. We know that this node returns complex data, so we can type cast to UAGenericObject.
            UAGenericObject genericObject;
            try
            {
                genericObject = (UAGenericObject)client.ReadValue(endpointDescriptor, nodeDescriptor);
            }
            catch (UAException uaException)
            {
                Console.WriteLine("*** Failure: {0}", uaException.GetBaseException().Message);
                return;
            }
            // The data type is in the GenericData.DataType property of the UAGenericObject.
            DataType dataType = genericObject.GenericData.DataType;

            // Process the data type. We will inspect some of its properties, and dump them.
            ProcessDataType(dataType, maximumDepth: 3);
        }
        

        // Process the data type. It can be recursive in itself, so if you do not know the data type you are dealing with, 
        // it is recommended to make safeguards against infinite looping or recursion - here, the maximumDepth.
        public static void ProcessDataType(DataType dataType, int maximumDepth)
        {
            if (maximumDepth == 0)
                return;

            Console.WriteLine();
            Console.WriteLine("dataType.Name: {0}", dataType.Name);

            switch (dataType.Kind)
            {
                case DataTypeKind.Enumeration:
                    Console.WriteLine("The data type is an enumeration.");
                    var enumerationDataType = (EnumerationDataType) dataType;
                    Console.WriteLine("It has {0} enumeration members.", enumerationDataType.EnumerationMembers.Count);
                    Console.WriteLine("The names of the enumeration members are: {0}.",
                        String.Join(", ", enumerationDataType.EnumerationMembers.Select(member => member.Name)));
                    // Here you can process the members, or inspect SizeInBits etc.
                    break;

                case DataTypeKind.Opaque:
                    Console.WriteLine("The data type is opaque.");
                    var opaqueDataType = (OpaqueDataType) dataType;
                    Console.WriteLine("Its size is {0} bits.", opaqueDataType.SizeInBits);
                    // There isn't much more you can learn about an opaque data type (well, it may have Description and 
                    // other common members). It is, after all, opaque...
                    break;

                case DataTypeKind.Primitive:
                    Console.WriteLine("The data type is primitive.");
                    var primitiveDataType = (PrimitiveDataType) dataType;
                    Console.WriteLine("Its .NET value type is \"{0}\".", primitiveDataType.ValueType);
                    // There isn't much more you can learn about the primitive data type.
                    break;

                case DataTypeKind.Sequence:
                    Console.WriteLine("The data type is a sequence.");
                    var sequenceDataType = (SequenceDataType) dataType;
                    Console.WriteLine("Its length is {0} (-1 means that the length can vary).", sequenceDataType.Length);

                    Console.WriteLine("A dump of the element data type follows.");
                    ProcessDataType(sequenceDataType.ElementDataType, maximumDepth - 1);
                    break;

                case DataTypeKind.Structured:
                    Console.WriteLine("The data type is structured.");
                    var structuredDataType = (StructuredDataType) dataType;
                    Console.WriteLine("It has {0} data fields.", structuredDataType.DataFields.Count);
                    Console.WriteLine("The names of the data fields are: {0}.",
                        String.Join(", ", structuredDataType.DataFields.Select(field => field.Name)));

                    Console.WriteLine("A dump of each of the data fields follows.");
                    foreach (DataField dataField in structuredDataType.DataFields)
                    {
                        Console.WriteLine();
                        Console.WriteLine("dataField.Name: {0}", dataField.Name);
                        // Note that every data field also has properties like IsLength, IsOptional, IsSwitch which might 
                        // be of interest, but we are not dumping them here.
                        ProcessDataType(dataField.DataType, maximumDepth - 1);
                    }
                    break;

                case DataTypeKind.Union:
                    Console.WriteLine("The data type is union.");
                    var unionDataType = (UnionDataType)dataType;
                    Console.WriteLine("It has {0} data fields.", unionDataType.DataFields.Count);
                    Console.WriteLine("The names of the data fields are: {0}.",
                        String.Join(", ", unionDataType.DataFields.Select(field => field.Name)));
                    break;
            }
        }
    }
}
// Shows how to process a data type, displaying some of its properties, recursively.

class procedure Kind.Main;
var
  Client: _EasyUAClient;
  DataType: OpcLabs_BaseLib_TLB._DataType;
  EndpointDescriptor: string;
  GenericObject: _UAGenericObject;
  NodeDescriptor: string;
begin
  // Define which server and node we will work with.
  EndpointDescriptor := 
    //'http://opcua.demo-this.com:51211/UA/SampleServer';
    //'https://opcua.demo-this.com:51212/UA/SampleServer/';
    'opc.tcp://opcua.demo-this.com:51210/UA/SampleServer';
  NodeDescriptor := 'nsu=http://test.org/UA/Data/ ;i=10239';  // [ObjectsFolder]/Data.Static.Scalar.StructureValue

  // Instantiate the client object
  Client := CoEasyUAClient.Create;

  // Read a node. We know that this node returns complex data, so we can type cast to UAGenericObject.

  try
    GenericObject := IUnknown(Client.ReadValue(EndpointDescriptor, NodeDescriptor)) as _UAGenericObject;
  except
    on E: EOleException do
    begin
      WriteLn(Format('*** Failure: %s', [E.GetBaseException.Message]));
      Exit;
    end;
  end;

  // The data type is in the GenericData.DataType property of the UAGenericObject.
  DataType := genericObject.GenericData.DataType;

  // Process the data type. We will inspect some of its properties, and dump them.
  ProcessDataType(DataType, 2);
end;

// Process the data type. It can be recursive in itself, so if you do not know the data type you are dealing with,
// it is recommended to make safeguards against infinite looping or recursion - here, the maximumDepth.
class procedure Kind.ProcessDataType(DataType: OpcLabs_BaseLib_TLB._DataType; MaximumDepth: Cardinal);
var
  Count: Cardinal;
  DataField: _DataField;
  Element: OleVariant;
  ElementEnumerator: IEnumVARIANT;
  EnumerationMember: _EnumerationMember;
  EnumerationDataType: _EnumerationDataType;
  FieldNames: string;
  First: boolean;
  MemberNames: string;
  OpaqueDataType: _OpaqueDataType;
  PrimitiveDataType: _PrimitiveDataType;
  SequenceDataType: _SequenceDataType;
  StructuredDataType: _StructuredDataType;
  TypeName: WideString;
begin
  if MaximumDepth = 0 then
    Exit;

  WriteLn;
  WriteLn('dataType.Name: ', DataType.Name);

  case DataType.Kind of
    DataTypeKind_Enumeration:
      begin
        WriteLn('The data type is an enumeration.');
        EnumerationDataType := DataType as _EnumerationDataType;
        WriteLn(Format('It has %s enumeration members.', [EnumerationDataType.EnumerationMembers.Count]));
        ElementEnumerator := EnumerationDataType.EnumerationMembers.GetEnumerator;
        MemberNames := '';
        First := True;
        while (ElementEnumerator.Next(1, Element, Count) = S_OK) do
        begin
          EnumerationMember := IUnknown(Element) as _EnumerationMember;
          if First then
            First := False
          else
            MemberNames := MemberNames + ', ';
          MemberNames := MemberNames + EnumerationMember.Name;
        end;
        WriteLn(Format('The names of the enumeration members are: %s.', [MemberNames]));
        // Here you can process the members, or inspect SizeInBits etc.
      end;
    DataTypeKind_Opaque:
      begin
        WriteLn('The data type is opaque.');
        OpaqueDataType := DataType as _OpaqueDataType;
        WriteLn(Format('Its size is %s bits.', [OpaqueDataType.SizeInBits]));
        // There isn't much more you can learn about an opaque data type (well, it may have Description and
        // other common members). It is, after all, opaque...
      end;
    DataTypeKind_Primitive:
      begin
        WriteLn('The data type is primitive.');
        PrimitiveDataType := DataType as _PrimitiveDataType;
        PrimitiveDataType.ValueType.Get_ToString(TypeName);
        WriteLn(Format('Its .NET value type is "%s".', [TypeName]));
        // There isn't much more you can learn about the primitive data type.
      end;
    DataTypeKind_Sequence:
      begin
        WriteLn('The data type is a sequence.');
        SequenceDataType := DataType as _SequenceDataType;
        WriteLn(Format('Its length is %s (-1 means that the length can vary).', [SequenceDataType.Length.ToString]));
        WriteLn('A dump of the element data type follows.');
        ProcessDataType(SequenceDataType.ElementDataType, MaximumDepth - 1);
      end;
    DataTypeKind_Structured:
      begin
        WriteLn('The data type is structured.');
        StructuredDataType := DataType as _StructuredDataType;
        WriteLn(Format('It has %s data fields.', [StructuredDataType.DataFields.Count.ToString]));
        ElementEnumerator := StructuredDataType.DataFields.GetEnumerator;
        FieldNames := '';
        First := True;
        while (ElementEnumerator.Next(1, Element, Count) = S_OK) do
        begin
          if First then
            First := False
          else
            FieldNames := FieldNames + ', ';
          FieldNames := FieldNames + Element.Name;
        end;
        WriteLn(Format('The names of the data fields are: %s.', [FieldNames]));

        WriteLn('A dump of each of the data fields follows.');
        ElementEnumerator := StructuredDataType.DataFields.GetEnumerator;
        while (ElementEnumerator.Next(1, Element, Count) = S_OK) do
        begin
          DataField := IUnknown(Element) as _DataField;
          WriteLn;
          WriteLn(Format('dataField.Name: %s', [DataField.Name]));
          // Note that every data field also has properties like IsLength, IsOptional, IsSwitch which might
          // be of interest but we are not dumping them here.
          ProcessDataType(DataField.DataType, MaximumDepth - 1);
        end;
    end;
  end;

end;

// Shows how to process generic data type, displaying some of its properties, recursively.

using System;
using System.Collections.Generic;
using OpcLabs.BaseLib.DataTypeModel;
using OpcLabs.EasyOpc.UA;
using OpcLabs.EasyOpc.UA.ComplexData;
using OpcLabs.EasyOpc.UA.OperationModel;

namespace UADocExamples.ComplexData._GenericData
{
    class DataTypeKind1
    {
        public static void Main1()
        {
            // Define which server and node we will work with.
            UAEndpointDescriptor endpointDescriptor =
                "opc.tcp://opcua.demo-this.com:51210/UA/SampleServer";
            // or "http://opcua.demo-this.com:51211/UA/SampleServer" (currently not supported)
            // or "https://opcua.demo-this.com:51212/UA/SampleServer/"
            UANodeDescriptor nodeDescriptor =
                "nsu=http://test.org/UA/Data/ ;i=10239"; // [ObjectsFolder]/Data.Static.Scalar.StructureValue

            // Instantiate the client object.
            var client = new EasyUAClient();

            // Read a node. We know that this node returns complex data, so we can type cast to UAGenericObject.
            UAGenericObject genericObject;
            try
            {
                genericObject = (UAGenericObject)client.ReadValue(endpointDescriptor, nodeDescriptor);
            }
            catch (UAException uaException)
            {
                Console.WriteLine("*** Failure: {0}", uaException.GetBaseException().Message);
                return;
            }

            // Process the generic data type. We will inspect some of its properties, and dump them.
            ProcessGenericData(genericObject.GenericData, maximumDepth: 3);
        }
        

        // Process the generic data type. Its structure can sometimes be quite deep, therefore we are limiting the depth
        // of the recursion using maximumDepth.
        public static void ProcessGenericData(GenericData genericData, int maximumDepth)
        {
            if (maximumDepth == 0)
                return;

            Console.WriteLine();
            Console.WriteLine("genericData.DataType: {0}", genericData.DataType);

            switch (genericData.DataTypeKind)
            {
                case DataTypeKind.Enumeration:
                    Console.WriteLine("The generic data is an enumeration.");
                    var enumerationData = (EnumerationData) genericData;
                    Console.WriteLine("Its value is {0}.", enumerationData.Value);
                    // There is also a ValueName that you can inspect (if known).
                    break;

                case DataTypeKind.Opaque:
                    Console.WriteLine("The generic data is opaque.");
                    var opaqueData = (OpaqueData) genericData;
                    Console.WriteLine("Its size is {0} bits.", opaqueData.SizeInBits);
                    Console.WriteLine("The data bytes are {0}.", BitConverter.ToString(opaqueData.ByteArray));
                    // Use the Value property (a BitArray) if you need to access the value bit by bit.
                    break;

                case DataTypeKind.Primitive:
                    Console.WriteLine("The generic data is primitive.");
                    var primitiveData = (PrimitiveData) genericData;
                    Console.WriteLine("Its value is \"{0}\".", primitiveData.Value);
                    break;

                case DataTypeKind.Sequence:
                    Console.WriteLine("The generic data is a sequence.");
                    var sequenceData = (SequenceData) genericData;
                    Console.WriteLine("It has {0} elements.", sequenceData.Elements.Count);
                    Console.WriteLine("A dump of the elements follows.");
                    foreach (GenericData element in sequenceData.Elements)
                        ProcessGenericData(element, maximumDepth - 1);
                    break;

                case DataTypeKind.Structured:
                    Console.WriteLine("The generic data is structured.");
                    var structuredData = (StructuredData) genericData;
                    Console.WriteLine("It has {0} field data members.", structuredData.FieldData.Count);
                    Console.WriteLine("The names of the fields are: {0}.",
                        String.Join(", ", structuredData.FieldData.Keys));

                    Console.WriteLine("A dump of each of the fields follows.");
                    foreach (KeyValuePair<string, GenericData> pair in structuredData.FieldData)
                    {
                        Console.WriteLine();
                        Console.WriteLine("Field name: {0}", pair.Key);
                        ProcessGenericData(pair.Value, maximumDepth - 1);
                    }
                    break;

                case DataTypeKind.Union:
                    Console.WriteLine("The generic data is a union.");
                    var unionData = (UnionData)genericData;
                    Console.WriteLine("The name of current field is: {0}", unionData.FieldName);
                    Console.WriteLine("Current field value is: {0}", unionData.FieldValue);
                    break;
            }
        }
    }
}
// Shows how to process generic data type, displaying some of its properties, recursively

class procedure DataTypeKind1.Main;
var
  Client: _EasyUAClient;
  EndpointDescriptor: string;
  GenericObject: _UAGenericObject;
  NodeDescriptor: string;
begin
  EndpointDescriptor := 
    //'http://opcua.demo-this.com:51211/UA/SampleServer';
    //'https://opcua.demo-this.com:51212/UA/SampleServer/';
    'opc.tcp://opcua.demo-this.com:51210/UA/SampleServer';
  NodeDescriptor := 'nsu=http://test.org/UA/Data/ ;i=10239';  // [ObjectsFolder]/Data.Static.Scalar.StructureValue

  // Instantiate the client object
  Client := CoEasyUAClient.Create;

  // Read a node. We know that this node returns complex data, so we can type cast to UAGenericObject.

  try
    GenericObject := _UAGenericObject(IUnknown(Client.ReadValue(EndpointDescriptor, NodeDescriptor)));
  except
    on E: EOleException do
    begin
      WriteLn(Format('*** Failure: %s', [E.GetBaseException.Message]));
      Exit;
    end;
  end;

  // Process the generic data type. We will inspect some of its properties, and dump them.
  ProcessGenericData(GenericObject.GenericData, 2);
end;

Function VariantToBytes(Const Value: OleVariant): TBytes;
Var
  Size: Integer;
  pData: Pointer;
Begin
  Size := Succ(VarArrayHighBound(Value, 1) - VarArrayLowBound(Value, 1));
  SetLength(Result, Size);
  pData := VarArrayLock(Value);
  Try
    Move(pData^, Pointer(Result)^, Size);
  Finally
    VarArrayUnlock(Value);
  End;
End;

class procedure DatatypeKind1.ProcessGenericData(GenericData: OpcLabs_BaseLib_TLB._GenericData; MaximumDepth: Cardinal);
var
  ByteArray: OleVariant;
  Count: Cardinal;
  Element: OleVariant;
  ElementEnumerator: IEnumVARIANT;
  EnumerationData: _EnumerationData;
  First: boolean;
  Keys: string;
  OpaqueData: _OpaqueData;
  PrimitiveData: _PrimitiveData;
  SequenceData: _SequenceData;
  StructuredData: _StructuredData;
  Value: OpcLabs_BaseLib_TLB._GenericData;
begin
  if MaximumDepth = 0 then
    Exit;

  WriteLn;
  WriteLn('genericData.DataType: ', GenericData.DataType.ToString);

  case GenericData.DataTypeKind of
    DataTypeKind_Enumeration:
      begin
        WriteLn('The generic data is an enumeration.');
        EnumerationData := GenericData as _EnumerationData;
        WriteLn(Format('Its value is %s.', [EnumerationData.Value.ToString]));
        // There is also a ValueName that you can inspect (if known).
      end;
    DataTypeKind_Opaque:
      begin
        WriteLn('The generic data is opaque.');
        OpaqueData := GenericData as _OpaqueData;
        WriteLn(Format('Its size is %d bits.', [OpaqueData.SizeInBits]));
        TVarData(ByteArray).VType := varArray;
        TVarData(ByteArray).VArray := PVarArray(OpaqueData.ByteArray);
        WriteLn(Format('The data bytes are %s.', [TEncoding.ANSI.GetString(VariantToBytes(ByteArray))]));
        // Use the Value property (a BitArray) if you need to access the value bit by bit.
      end;
    DataTypeKind_Primitive:
      begin
        WriteLn('The generic data is primitive.');
        PrimitiveData := GenericData as _PrimitiveData;
        WriteLn(Format('Its value is "%s".', [PrimitiveData.Value]));
      end;
    DataTypeKind_Sequence:
      begin
        WriteLn('The generic data is a sequence.');
        SequenceData := GenericData as _SequenceData;
        WriteLn(Format('It has %s elements.', [SequenceData.Elements.Count.ToString]));
        WriteLn('A dump of the elements follows.');
        ElementEnumerator := SequenceData.Elements.GetEnumerator;
        while (ElementEnumerator.Next(1, Element, Count) = S_OK) do
        begin
          ProcessGenericData(IUnknown(Element) as OpcLabs_BaseLib_TLB._GenericData, MaximumDepth - 1);
        end;
      end;
    DataTypeKind_Structured:
      begin
        WriteLn('The generic data is structured.');
        StructuredData := GenericData as _StructuredData;
        WriteLn(Format('It has %s field data members.', [StructuredData.FieldData.Count.ToString]));
        ElementEnumerator := StructuredData.FieldData.GetEnumerator;
        Keys := '';
        First := True;
        while (ElementEnumerator.Next(1, Element, Count) = S_OK) do
        begin
          if First then
            First := False
          else
            Keys := Keys + ', ';
          Keys := Keys + Element.Key;
        end;
        WriteLn(Format('The names of the fields are: %s.', [Keys]));

        WriteLn('A dump of each of the fields follows.');
        ElementEnumerator := StructuredData.FieldData.GetEnumerator;
        while (ElementEnumerator.Next(1, Element, Count) = S_OK) do
        begin
          WriteLn;
          WriteLn(Format('Field name: %s', [Element.Key]));
          Value := IUnknown(Element.Value) as OpcLabs_BaseLib_TLB._GenericData;
          ProcessGenericData(Value, MaximumDepth - 1);
        end;
      end;
  end;

end;

Inheritance Hierarchy

System.Object
   System.ValueType
      System.Enum
         OpcLabs.BaseLib.DataTypeModel.DataTypeKind

Requirements

Target Platforms: .NET Framework: Windows 10 (selected versions), Windows 11 (selected versions), Windows Server 2016, Windows Server 2022; .NET: Linux, macOS, Microsoft Windows

See Also