private void WriteOptionalProperty(IndentedTextWriter writer, ClassDefinition.Property p, int index, bool parentHasOptionalFields)
        {
            WritePropertyDocumentation(writer, p, isUnion: false);

            var type  = RenderType(p, isOptional: true);
            var field = GetFieldName(p.SymbolicName);

            writer.WriteLine($"public {type} {p.SymbolicName}");
            writer.Begin("{");
            writer.WriteLine($"get => {field};");
            writer.WriteLine("set");
            writer.Begin("{");
            if (parentHasOptionalFields)
            {
                writer.WriteLine($"uint flag = 1u << ({index} + base.OptionalFieldCount);");
            }
            else
            {
                writer.WriteLine($"uint flag = 1u << {index};");
            }
            writer.WriteLine();
            writer.WriteLine($"{field} = value;");
            writer.WriteLine("EncodingMask = value is null");
            writer.Indent++;
            writer.WriteLine("? EncodingMask & ~flag");
            writer.WriteLine(": EncodingMask | flag;");
            writer.Indent--;
            writer.End("}");
            writer.End("}");
            writer.WriteLine($"private {type} {field};");
        }
        private void WritePropertyDocumentation(IndentedTextWriter writer, ClassDefinition.Property p, bool isUnion)
        {
            string summary = p.Description is null
                ? $"The {p.OpcUaName} property."
                : p.Description;

            writer.WriteLine("/// <summary>");
            foreach (var line in summary.WordWrap(76 - 4 * writer.Indent))
            {
                writer.WriteLine($"/// {line}");
            }
            writer.WriteLine("/// </summary>");

            if (isUnion)
            {
                var remarks = "The value of this property may only be retrieved, when "
                              + $"the <see cref=\"SwitchField\" /> property.is set to <c>UnionField.{p.SymbolicName}</c>. "
                              + "Otherwise the behavior is undefined and can lead to invalid data or "
                              + "an <see cref=\"System.InvalidCastException\" /> exeption.";
                writer.WriteLine("/// <remarks>");
                foreach (var line in remarks.WordWrap(76 - 4 * writer.Indent))
                {
                    writer.WriteLine($"/// {line}");
                }
                writer.WriteLine("/// </remarks>");
            }

            if (!string.IsNullOrEmpty(p.Documentation))
            {
                writer.WriteLine($"/// <seealso href=\"{p.Documentation}\" />");
            }
        }
        private void WriteProperty(IndentedTextWriter writer, ClassDefinition.Property p)
        {
            WritePropertyDocumentation(writer, p, isUnion: false);
            var type = RenderType(p);

            writer.WriteLine($"public {type} {p.SymbolicName} {{ get; set; }}");
        }
        private string RenderType(ClassDefinition.Property p, bool isOptional = false)
        {
            var netType = _typeSet.GetNetType(p.DataTypeId);
            var r       = p.Rank switch
            {
                2 => "[,]",
                1 => "[]",
                _ => ""
            };
            var q     = (!isOptional || netType.IsReference || p.Rank > 0) ? "" : "?";
            var field = GetFieldName(p.SymbolicName);

            return($"{netType.TypeName}{r}{q}");
        }
        private void WriteUnionProperty(IndentedTextWriter writer, ClassDefinition.Property p)
        {
            WritePropertyDocumentation(writer, p, isUnion: true);
            var netType = _typeSet.GetNetType(p.DataTypeId);
            var r       = p.Rank switch
            {
                2 => "[,]",
                1 => "[]",
                _ => ""
            };
            var type = $"{netType.TypeName}{r}";

            writer.WriteLine($"public {type} {p.SymbolicName}");
            writer.Begin("{");
            writer.WriteLine($"get => ({type})_field;");
            writer.WriteLine("set");
            writer.Begin("{");
            writer.WriteLine($"SwitchField = UnionField.{p.SymbolicName};");
            writer.WriteLine($"_field = value;");
            writer.End("}");
            writer.End("}");
        }