mirror of
https://github.com/OPCFoundation/UA-.NETStandard.git
synced 2026-10-23 18:39:26 +08:00
442889cba5
# Description
This PR fixes a bug audit of the source generation projects
(`tools/Opc.Ua.SourceGeneration*`: model loading, NodeSet import, all
emitters, the Roslyn hosts and packaging). It also fixes a max-effort
code review of those fixes, and a check of every spec-relevant change
against the OPC UA 1.05 text.
- **Scope:** about 85 audit findings, 48 review findings and 32
spec-grounding items were addressed. Each fix has a regression test that
fails without it.
- **Wire change:** it includes one deliberate, stack-wide wire change:
**structure-field matrices now follow OPC 10000-6 5.2.5 Table 28**.
Most changes are internal correctness fixes. The sections below list
every change a user can observe: wire formats, generated code and API,
generated address-space content, diagnostics and runtime behaviour.
## Behaviour / user-facing changes
### Wire format (encoders)
- **Binary inline matrices** (OPC 10000-6 5.2.5 Table 28).
- **Layout:** a multi-dimensional *structure field* is encoded as
`Int32[] Dimensions`, then the values **without a length prefix**, with
at least 2 dimensions.
- **Empty and null:** any dimension <= 0 means no values follow, and a
null matrix is `-1`. An empty matrix is written as `[0,0]`.
- **Compatibility:** this is **not compatible with earlier builds of
this SDK** for matrix fields. It applies to generated types,
`[DataType]` types, `Structure`, client ComplexTypes and
`WriteEncodeableMatrix`.
- **Unchanged:** Variant matrices (5.2.2.16) keep their old encoding.
- **Declared rank decides matrix vs array.** A 1-D `MatrixOf<T>` in an
array field or a Variable value is written as an array again.
Matrix-declared fields go through the new public
`EncoderExtensions.WriteInlineMatrixValue`, which generated code also
uses. A non-empty 1-D value in a matrix field throws `BadEncodingError`.
- **Decoder hardening:**
- Before allocating, the decoder bounds all matrix dimensions against
overflow, `MaxArrayLength` and the remaining message length.
- The decoder rejects:
- a matrix with fewer than 2 dimensions;
- a populated matrix whose rank differs from the field's declared rank;
- a union SwitchField greater than the number of fields;
- an EncodingMask with unassigned bits set.
- **Encoder `MaxArrayLength`:** the encoder enforces `MaxArrayLength`
for inline matrices, as it already did for arrays.
- **XML structure fields** (5.3.1, 5.3.4, 5.3.5).
- **Fields:** `Structure` and client ComplexTypes write fields like
typed fields (`<A>1</A>`, array elements directly) instead of a Variant
body.
- **Matrix fields:** `Dimensions` and `Elements` go directly inside the
field element, with no `<Matrix>` wrapper.
- **Empty matrices:** written as nil, because XML dimensions must be
greater than 0.
- **Compatibility:** decoders still accept the old shapes.
- **Enum fixes:** enum array elements with value 0 are no longer
dropped, and enum array element names are fixed.
- **Other encoding fixes:**
- A null `DiagnosticInfo` structure field writes `0x00` instead of
nothing.
- A null scalar field in a runtime `Structure` is written as its default
instead of zero bytes, which used to shift every following field.
- A Variant holding an empty matrix encodes as an empty array instead of
throwing.
- `Variant.Copy` keeps the matrix identity of null and empty matrices.
- **NodeSet export and the DataContract surrogate** write Variable
values with the Variant rules again. A null or empty `MatrixOf` variable
no longer produces invalid XML or unreadable NodeSets.
- **`JsonEncoder.CanOmitFields`** is `true` only for Compact encoding.
Verbose and RawData JSON include default-valued fields.
### `[DataType]` source-generated types
- **Default-value handling** (OPC 10000-6 5.4.1, Table 1).
- **Encode:** a field is omitted only when its value *and* its declared
default are the type's default (0, false, null). Fields with a
non-default initializer or constructor default, and empty strings, are
always written, so configuration files get slightly larger.
- **JSON decode:** a field missing from JSON decodes to the type
default.
- **XML decode:** a field missing from XML keeps its declared default,
which older configuration files rely on.
- **Why:** this fixes silent round-trip loss, for example
`SamplingInterval = 0` read back as `-1`.
- **Nested `[DataType]` types:** they are now generated inside their
containing types. Without an explicit id, their default TypeId and
XmlName are qualified (e.g. `s=Outer.Foo`); **wire identity change** for
nested types. Colliding activator names get a `_2` suffix.
- **Activators:** they are `internal` when the type, or any containing
type, is not public (was CS0060).
- **Matrix properties:**
- `MatrixOf<T>` properties use the inline matrix encoding.
- Matrices of non-sealed structures, or with
`StructureHandling.ExtensionObject`, are written as ExtensionObjects.
- Their published ValueRank is 2, because the rank can't be known from
`MatrixOf<T>`.
- **Published StructureDefinitions:**
- They include base-class fields.
- Nullable properties are no longer marked optional.
- Inline structure fields name their concrete type.
- **`[Flags]` enums:** they are published as plain enumerations with
their member values, which matches how they are encoded.
- **Other generated code:**
- `Clone` deep-copies arrays and matrices of structures, Variants,
ExtensionObjects and DataValues.
- `IsEqual` and `GetHashCode` are consistent: EncodingMask, active union
member and NaN handling agree.
- Pooled `Reuse()` restores the freshly constructed state through the
new `protected virtual ResetForReuse()`, and returns an instance to its
runtime type's pool.
- **Enum capture:** enum member values are captured culture-invariantly.
Negative values were lost on cultures that use U+2212 as the minus sign.
### Model-driven generator: generated code, API and file names
- **Removed API:** generated `*_Placeholder` proxy accessors (e.g.
`PowerTrainTypeClient.GetMotorIdentifier_PlaceholderAsync`) and fluent
`X_Placeholder()` accessors are removed; they could never resolve
anything.
- Proxy accessors now look children up by BrowseName with the right
namespace.
- `RoboticsClient` finds motors and gears by type and drives via
`IsDrivenBy`. Its topology snapshots used to be empty.
- **Renamed files:** generated files for a bound `[NodeManager]` are now
named `{Namespace}.{Class}.NodeManager.g.cs` (also `.Factory` and
`.FluentBuilders`).
- **Generated NodeState code:**
- Attributes are set through `baseState`/`nodeState` locals, so children
named like base attributes (e.g. `DataType`, `EventNotifier`) compile.
- Children that hide base members are declared `public new`, using names
reflected from the runtime.
- `global::` qualification is used throughout.
- **Proxies and fluent builders:** a proxy whose supertype is excluded
(e.g. Draft) derives from the nearest emitted ancestor. Fluent wrappers
and NodeState factories fall back the same way; they used to fail with
CS0246.
- **Derived structures:**
- The optional-field `EncodingMask` continues across inheritance.
- A derived structure over a base type from another model no longer
relies on `base.ResetForReuse`.
- **Default values:**
- NodeId, QualifiedName and ExpandedNodeId defaults resolve by namespace
URI (`context.NamespaceUris.GetIndexOrAppend`) and server URI.
- StatusCode, negative enum, `double`/`float` (shortest round-trip
literal) and escaped string defaults now compile.
- **Event records:**
- Vendor event records have `Decoder.GetStandardFields(NamespaceTable)`,
and their browse paths use the model's namespace.
- A field whose namespace is unknown to the session no longer matches a
namespace-0 field.
- Companion `StandardFields` is `[Obsolete]`.
- Vendor simple subtypes such as `Percent : Double` map to their
built-in type.
- **Other fixes:**
- `MethodState.CallAsync` passes the real `objectId` to synchronous
`OnCallMethod2` handlers; it used to pass `NodeId.Null`.
- Enumeration fields with an explicit `Identifier` keep it, instead of
taking a trailing `_<digits>`.
- Explicit NumericIds are no longer reused by automatic numbering.
- Dependencies are loaded in topological order.
### Generated address-space content
- **Arguments:**
- Methods without arguments no longer get empty
`InputArguments`/`OutputArguments` properties (OPC 10000-3 5.7).
- About 2,660 automatically assigned namespace-0 NodeIds of 15000 and
above shift. Every NodeId in `StandardTypes.csv` is unchanged.
- **Permissions:** type nodes and method declarations on types now carry
the model's `RolePermissions`/`AccessRestrictions`.
- **Restored nodes:** NodeSet import keeps nodes that were silently
dropped before:
- `NamespaceMetadata` objects and the NodeSet's own TypeDictionary
variables;
- ISA95 placeholders linked only non-hierarchically;
- instances whose parent is in another namespace.
- **Import details:**
- ValueRank > 1 without ArrayDimensions keeps its rank.
- `svr=` indexes map correctly.
- Invalid MinimumSamplingInterval values import as -1, not 0.
- Localized texts prefer the invariant or English translation.
- **StructureDefinitions:**
- They include inherited fields, including for subtypes without their
own fields (e.g. `AnonymousIdentityToken` now publishes PolicyId).
- The StructureType kind covers inherited AllowSubTypes fields.
- Unions ignore IsOptional.
- StructureFields never publish ValueRank 0; a OneOrMoreDimensions field
without dimensions becomes rank 2.
- Fields with ValueRank -2/-3 are published as scalar BaseDataType,
which is what is on the wire.
- **OptionSets:**
- Implicit fields get the next free bit.
- `OptionSetValues` uses null for undefined bits instead of "Reserved",
and structure OptionSets publish all their bits (no 32/96-bit cap).
- Numeric OptionSets are limited to their base type's width, and UInt64
bit 63 works.
- **Schemas:**
- Structures with inline-matrix fields are left out of the `.bsd`
(5.2.5).
- In the BSD, Variant-encoded and non-structure subtyped fields are
described as `ua:Variant`.
- In the `.xsd`, matrix fields are typed `ua:Matrix` with
`Dimensions`/`Elements`, and `EncodingMask` is required.
### NodeSet / model input handling
- **Model selection:**
- The newest NodeSet of a model is chosen by `ModelVersion` (SemVer 2.0
precedence), then PublicationDate. The `Version` attribute, which Annex
F says is not for comparison, is only a tie-break.
- The order is total and does not depend on input order; referenced
assemblies use the same rule.
- **Default names:**
- Invalid default Name/Prefix values are repaired (`201301ISA95` becomes
`_201301ISA95`, `class` becomes `class_`).
- Valid names are unchanged.
- Sanitising no longer depends on the OS.
- **`ModelUri` metadata** that doesn't match the NodeSet raises a
warning instead of silently losing the model.
- **Input detection:**
- Only XML files whose root is `ModelDesign` or `UANodeSet` are treated
as models.
- A malformed NodeSet stays a NodeSet input, so it no longer breaks the
ModelDesign pass.
- **`IdentifierFile` paths:** they are normalized (`./`, `../`), and the
suffix match requires a folder boundary.
- **Dependency payloads** (`ModelDependencyV1`) carry field IsOptional,
AllowSubTypes, ArrayDimensions and the producer's namespace tables in
skippable trailers, so old and new readers stay compatible.
### Roslyn host, diagnostics, packaging
- **New diagnostics:**
- MODELGEN036: `[NodeManager]` target not supported (nested, generic,
file-local or global namespace).
- MODELGEN037: `[DataType]` target not supported (struct, generic,
abstract, file-local or global namespace).
- MODELGEN038: the definition of an encodeable base type can't be found.
- **New validator errors:**
- a structure with both optional and subtyped fields (OPC 10000-6 F.13);
- multi-bit or duplicate OptionSet masks.
- **Diagnostic locations:** `[DataType]`/`[NodeManager]` diagnostics
point at real source locations again, so `#pragma` and `.editorconfig`
apply. MODELGEN010 is the exception.
- **Incremental caching:** pipeline values compare by value, so
unrelated edits no longer regenerate the whole model or all
`[DataType]`s.
- **`ModelSourceGeneratorIgnore`** on a ModelDesign input is honoured;
the design still resolves as a dependency.
- **Cancellation:** a cancelled generation run propagates
`OperationCanceledException` instead of reporting a MODELGEN003 error.
- **Stack package:** the `Stack` NuGet package now ships
`build/OPCFoundation.NetStandard.Opc.Ua.SourceGeneration.Stack.props`,
so `StackSourceGeneratorMode` and `StackSourceGeneratorExclude` reach
the compiler.
## Related Issues
- No tracking issue. The audit, review and spec-grounding reports are
available on request. Contains the matrix wire-format change discussed
for D-5 (OPC 10000-6 5.2.5 Table 28).
## Checklist
- [ ] I have signed the
[CLA](https://opcfoundation.org/license/cla/ContributorLicenseAgreementv1.0.pdf)
and read the
[CONTRIBUTING](https://github.com/OPCFoundation/UA-.NETStandard/blob/master/CONTRIBUTING.md)
doc.
- [x] I have added tests that prove my fix is effective or that my
feature works and increased code coverage.
- [x] I have added all necessary documentation.
(`docs/SourceGeneratedDataTypes.md`, `docs/NodeManagers.md`, generator
readme)
- [x] I have verified that my changes do not introduce (new) build or
analyzer warnings. (`UA.slnx` 0 warnings / 0 errors on net48 and
net10.0)
- [ ] I ran **all** tests locally using the **UA.slnx** solution against
at least .net **framework** and .net **10**, and all passed. The
affected suites were run on net10.0: SourceGeneration Core/Roslyn/Stack,
Types, Core.Encoders, Encoders.Fuzz, Client, Client.ComplexTypes,
PubSub, Core, Server, GDS, Configuration, Di, Robotics, ISA95,
Positioning, OpenUsd, XRegistry. net48 was built; its test legs, and the
post-rebase verification, run in CI.
- [ ] I fixed **all** failing and flaky tests in the CI pipelines and
**all** CodeQL warnings.
- [ ] I have addressed **all** PR feedback received.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2010 lines
62 KiB
C#
2010 lines
62 KiB
C#
/* ========================================================================
|
|
* Copyright (c) 2005-2025 The OPC Foundation, Inc. All rights reserved.
|
|
*
|
|
* OPC Foundation MIT License 1.00
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person
|
|
* obtaining a copy of this software and associated documentation
|
|
* files (the "Software"), to deal in the Software without
|
|
* restriction, including without limitation the rights to use,
|
|
* copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the
|
|
* Software is furnished to do so, subject to the following
|
|
* conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be
|
|
* included in all copies or substantial portions of the Software.
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
* OTHER DEALINGS IN THE SOFTWARE.
|
|
*
|
|
* The complete license agreement can be found here:
|
|
* http://opcfoundation.org/License/MIT/1.00/
|
|
* ======================================================================*/
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Xml;
|
|
using System.Xml.Serialization;
|
|
|
|
namespace Opc.Ua.Schema.Model
|
|
{
|
|
public partial class Namespace : IEquatable<Namespace>
|
|
{
|
|
/// <inheritdoc/>
|
|
public override bool Equals(object obj)
|
|
{
|
|
return obj is Namespace other && Equals(other);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public bool Equals(Namespace other)
|
|
{
|
|
if (ReferenceEquals(this, other))
|
|
{
|
|
return true;
|
|
}
|
|
return
|
|
other is not null &&
|
|
Name == other.Name &&
|
|
Prefix == other.Prefix &&
|
|
InternalPrefix == other.InternalPrefix &&
|
|
XmlNamespace == other.XmlNamespace &&
|
|
XmlPrefix == other.XmlPrefix &&
|
|
FilePath == other.FilePath &&
|
|
Version == other.Version &&
|
|
PublicationDate == other.PublicationDate &&
|
|
Value == other.Value;
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public override int GetHashCode()
|
|
{
|
|
var hash = new HashCode();
|
|
hash.Add(Name);
|
|
hash.Add(Prefix);
|
|
hash.Add(InternalPrefix);
|
|
hash.Add(XmlNamespace);
|
|
hash.Add(XmlPrefix);
|
|
hash.Add(FilePath);
|
|
hash.Add(Version);
|
|
hash.Add(PublicationDate);
|
|
hash.Add(Value);
|
|
return hash.ToHashCode();
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public static bool operator ==(Namespace left, Namespace right)
|
|
{
|
|
return EqualityComparer<Namespace>.Default.Equals(left, right);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public static bool operator !=(Namespace left, Namespace right)
|
|
{
|
|
return !(left == right);
|
|
}
|
|
}
|
|
|
|
public partial class ListOfChildren : IEquatable<ListOfChildren>
|
|
{
|
|
/// <inheritdoc/>
|
|
public override bool Equals(object obj)
|
|
{
|
|
return obj is ListOfChildren other && Equals(other);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public bool Equals(ListOfChildren other)
|
|
{
|
|
if (ReferenceEquals(this, other))
|
|
{
|
|
return true;
|
|
}
|
|
if (other is null)
|
|
{
|
|
return false;
|
|
}
|
|
if (other.Items is null || Items is null)
|
|
{
|
|
return other.Items == Items;
|
|
}
|
|
if (other.Items.Length != Items.Length)
|
|
{
|
|
return false;
|
|
}
|
|
// Only compare symbolicid to prevent circular loops
|
|
for (int ii = 0; ii < Items.Length; ii++)
|
|
{
|
|
if (!XmlQualifiedNameEqualityComparer.Default.Equals(
|
|
Items[ii].SymbolicId,
|
|
other.Items[ii].SymbolicId))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public override int GetHashCode()
|
|
{
|
|
if (Items is null || Items.Length == 0)
|
|
{
|
|
return 0;
|
|
}
|
|
var hash = new HashCode();
|
|
foreach (InstanceDesign child in Items)
|
|
{
|
|
hash.Add(XmlQualifiedNameEqualityComparer.Default.GetHashCode(child.SymbolicId));
|
|
}
|
|
return hash.ToHashCode();
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public static bool operator ==(ListOfChildren left, ListOfChildren right)
|
|
{
|
|
return EqualityComparer<ListOfChildren>.Default.Equals(left, right);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public static bool operator !=(ListOfChildren left, ListOfChildren right)
|
|
{
|
|
return !(left == right);
|
|
}
|
|
}
|
|
|
|
public partial class RolePermissionSet : IEquatable<RolePermissionSet>
|
|
{
|
|
/// <inheritdoc/>
|
|
public override bool Equals(object obj)
|
|
{
|
|
return obj is RolePermissionSet other && Equals(other);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public bool Equals(RolePermissionSet other)
|
|
{
|
|
if (ReferenceEquals(this, other))
|
|
{
|
|
return true;
|
|
}
|
|
return other is not null &&
|
|
ArrayEqualityComparer<RolePermission>.Default.Equals(RolePermission, other.RolePermission) &&
|
|
Name == other.Name &&
|
|
DoNotInheirit == other.DoNotInheirit;
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public override int GetHashCode()
|
|
{
|
|
var hash = new HashCode();
|
|
hash.Add(RolePermission, ArrayEqualityComparer<RolePermission>.Default);
|
|
hash.Add(Name);
|
|
hash.Add(DoNotInheirit);
|
|
return hash.ToHashCode();
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public static bool operator ==(RolePermissionSet left, RolePermissionSet right)
|
|
{
|
|
return EqualityComparer<RolePermissionSet>.Default.Equals(left, right);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public static bool operator !=(RolePermissionSet left, RolePermissionSet right)
|
|
{
|
|
return !(left == right);
|
|
}
|
|
}
|
|
|
|
public partial class RolePermission : IEquatable<RolePermission>
|
|
{
|
|
/// <inheritdoc/>
|
|
public override bool Equals(object obj)
|
|
{
|
|
return obj is RolePermission other && Equals(other);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public bool Equals(RolePermission other)
|
|
{
|
|
if (ReferenceEquals(this, other))
|
|
{
|
|
return true;
|
|
}
|
|
return other is not null &&
|
|
ArrayEqualityComparer<Permissions>.Default.Equals(Permission, other.Permission) &&
|
|
XmlQualifiedNameEqualityComparer.Default.Equals(Role, other.Role);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public override int GetHashCode()
|
|
{
|
|
var hash = new HashCode();
|
|
hash.Add(Permission, ArrayEqualityComparer<Permissions>.Default);
|
|
hash.Add(Role, XmlQualifiedNameEqualityComparer.Default);
|
|
return hash.ToHashCode();
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public static bool operator ==(RolePermission left, RolePermission right)
|
|
{
|
|
return EqualityComparer<RolePermission>.Default.Equals(left, right);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public static bool operator !=(RolePermission left, RolePermission right)
|
|
{
|
|
return !(left == right);
|
|
}
|
|
}
|
|
|
|
public partial class ReferenceTypeDesign : IEquatable<ReferenceTypeDesign>
|
|
{
|
|
/// <inheritdoc/>
|
|
public override bool Equals(object obj)
|
|
{
|
|
return obj is ReferenceTypeDesign other && Equals(other);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public bool Equals(ReferenceTypeDesign other)
|
|
{
|
|
if (ReferenceEquals(this, other))
|
|
{
|
|
return true;
|
|
}
|
|
return
|
|
other is not null &&
|
|
base.Equals(other) &&
|
|
EqualityComparer<LocalizedText>.Default.Equals(InverseName, other.InverseName) &&
|
|
Symmetric == other.Symmetric &&
|
|
SymmetricSpecified == other.SymmetricSpecified;
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public override int GetHashCode()
|
|
{
|
|
return HashCode.Combine(base.GetHashCode(), InverseName, Symmetric, SymmetricSpecified);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public static bool operator ==(ReferenceTypeDesign left, ReferenceTypeDesign right)
|
|
{
|
|
return EqualityComparer<ReferenceTypeDesign>.Default.Equals(left, right);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public static bool operator !=(ReferenceTypeDesign left, ReferenceTypeDesign right)
|
|
{
|
|
return !(left == right);
|
|
}
|
|
}
|
|
|
|
public partial class EncodingDesign : IEquatable<EncodingDesign>
|
|
{
|
|
/// <inheritdoc/>
|
|
public bool Equals(EncodingDesign other)
|
|
{
|
|
if (ReferenceEquals(this, other))
|
|
{
|
|
return true;
|
|
}
|
|
return other is not null && base.Equals(other);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public override bool Equals(object obj)
|
|
{
|
|
return obj is EncodingDesign other && base.Equals(other);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public override int GetHashCode()
|
|
{
|
|
return base.GetHashCode();
|
|
}
|
|
}
|
|
|
|
public partial class ObjectDesign : IEquatable<ObjectDesign>
|
|
{
|
|
/// <inheritdoc/>
|
|
public override bool Equals(object obj)
|
|
{
|
|
return obj is ObjectDesign other && Equals(other);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public bool Equals(ObjectDesign other)
|
|
{
|
|
if (ReferenceEquals(this, other))
|
|
{
|
|
return true;
|
|
}
|
|
return other is not null &&
|
|
base.Equals(other) &&
|
|
SupportsEvents == other.SupportsEvents &&
|
|
SupportsEventsSpecified == other.SupportsEventsSpecified;
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public override int GetHashCode()
|
|
{
|
|
return HashCode.Combine(base.GetHashCode(), SupportsEvents, SupportsEventsSpecified);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public static bool operator ==(ObjectDesign left, ObjectDesign right)
|
|
{
|
|
return EqualityComparer<ObjectDesign>.Default.Equals(left, right);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public static bool operator !=(ObjectDesign left, ObjectDesign right)
|
|
{
|
|
return !(left == right);
|
|
}
|
|
}
|
|
|
|
public partial class ObjectTypeDesign : IEquatable<ObjectTypeDesign>
|
|
{
|
|
/// <inheritdoc/>
|
|
public override bool Equals(object obj)
|
|
{
|
|
return obj is ObjectTypeDesign other && Equals(other);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public bool Equals(ObjectTypeDesign other)
|
|
{
|
|
if (ReferenceEquals(this, other))
|
|
{
|
|
return true;
|
|
}
|
|
return other is not null &&
|
|
base.Equals(other) &&
|
|
SupportsEvents == other.SupportsEvents &&
|
|
SupportsEventsSpecified == other.SupportsEventsSpecified;
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public override int GetHashCode()
|
|
{
|
|
return HashCode.Combine(base.GetHashCode(), SupportsEvents, SupportsEventsSpecified);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public static bool operator ==(ObjectTypeDesign left, ObjectTypeDesign right)
|
|
{
|
|
return EqualityComparer<ObjectTypeDesign>.Default.Equals(left, right);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public static bool operator !=(ObjectTypeDesign left, ObjectTypeDesign right)
|
|
{
|
|
return !(left == right);
|
|
}
|
|
}
|
|
|
|
public partial class DictionaryDesign : IEquatable<DictionaryDesign>
|
|
{
|
|
/// <inheritdoc/>
|
|
public override bool Equals(object obj)
|
|
{
|
|
return obj is DictionaryDesign other && Equals(other);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public bool Equals(DictionaryDesign other)
|
|
{
|
|
if (ReferenceEquals(this, other))
|
|
{
|
|
return true;
|
|
}
|
|
return
|
|
other is not null &&
|
|
base.Equals(other) &&
|
|
XmlQualifiedNameEqualityComparer.Default.Equals(EncodingName, other.EncodingName);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public override int GetHashCode()
|
|
{
|
|
var hash = new HashCode();
|
|
hash.Add(base.GetHashCode());
|
|
hash.Add(EncodingName, XmlQualifiedNameEqualityComparer.Default);
|
|
return hash.ToHashCode();
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public static bool operator ==(DictionaryDesign left, DictionaryDesign right)
|
|
{
|
|
return EqualityComparer<DictionaryDesign>.Default.Equals(left, right);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public static bool operator !=(DictionaryDesign left, DictionaryDesign right)
|
|
{
|
|
return !(left == right);
|
|
}
|
|
}
|
|
|
|
public partial class PropertyDesign : IEquatable<PropertyDesign>
|
|
{
|
|
/// <inheritdoc/>
|
|
public bool Equals(PropertyDesign other)
|
|
{
|
|
if (ReferenceEquals(this, other))
|
|
{
|
|
return true;
|
|
}
|
|
return other is not null && base.Equals(other);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public override bool Equals(object obj)
|
|
{
|
|
return obj is PropertyDesign other && Equals(other);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public override int GetHashCode()
|
|
{
|
|
return base.GetHashCode();
|
|
}
|
|
}
|
|
|
|
public partial class ViewDesign : IEquatable<ViewDesign>
|
|
{
|
|
/// <inheritdoc/>
|
|
public override bool Equals(object obj)
|
|
{
|
|
return obj is ViewDesign other && Equals(other);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public bool Equals(ViewDesign other)
|
|
{
|
|
if (ReferenceEquals(this, other))
|
|
{
|
|
return true;
|
|
}
|
|
return other is not null &&
|
|
base.Equals(other) &&
|
|
SupportsEvents == other.SupportsEvents &&
|
|
ContainsNoLoops == other.ContainsNoLoops;
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public override int GetHashCode()
|
|
{
|
|
return HashCode.Combine(base.GetHashCode(), SupportsEvents, ContainsNoLoops);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public static bool operator ==(ViewDesign left, ViewDesign right)
|
|
{
|
|
return EqualityComparer<ViewDesign>.Default.Equals(left, right);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public static bool operator !=(ViewDesign left, ViewDesign right)
|
|
{
|
|
return !(left == right);
|
|
}
|
|
}
|
|
|
|
public partial class ModelDesign : IEquatable<ModelDesign>
|
|
{
|
|
/// <summary>
|
|
/// Namespace table
|
|
/// </summary>
|
|
[XmlIgnore]
|
|
#pragma warning disable CA2235 // Mark all non-serializable fields
|
|
public NamespaceTable NamespaceUris { get; set; }
|
|
#pragma warning restore CA2235 // Mark all non-serializable fields
|
|
|
|
/// <summary>
|
|
/// Source file path
|
|
/// </summary>
|
|
[XmlIgnore]
|
|
public string SourceFilePath { get; set; }
|
|
|
|
/// <summary>
|
|
/// Is source node set
|
|
/// </summary>
|
|
[XmlIgnore]
|
|
public bool IsSourceNodeSet { get; set; }
|
|
|
|
/// <inheritdoc/>
|
|
public override bool Equals(object obj)
|
|
{
|
|
return obj is ModelDesign other && Equals(other);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public bool Equals(ModelDesign design)
|
|
{
|
|
if (ReferenceEquals(this, design))
|
|
{
|
|
return true;
|
|
}
|
|
return
|
|
ArrayEqualityComparer<Namespace>.Default.Equals(Namespaces, design.Namespaces) &&
|
|
ArrayEqualityComparer<RolePermissionSet>.Default.Equals(PermissionSets, design.PermissionSets) &&
|
|
ArrayEqualityComparer<NodeDesign>.Default.Equals(Items, design.Items) &&
|
|
XmlElementArrayStringEqualityComparer.Default.Equals(Extensions, design.Extensions) &&
|
|
TargetNamespace == design.TargetNamespace &&
|
|
TargetVersion == design.TargetVersion &&
|
|
TargetPublicationDate == design.TargetPublicationDate &&
|
|
TargetXmlNamespace == design.TargetXmlNamespace &&
|
|
DefaultLocale == design.DefaultLocale;
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public override int GetHashCode()
|
|
{
|
|
var hash = new HashCode();
|
|
hash.Add(Namespaces, ArrayEqualityComparer<Namespace>.Default);
|
|
hash.Add(PermissionSets, ArrayEqualityComparer<RolePermissionSet>.Default);
|
|
hash.Add(Items, ArrayEqualityComparer<NodeDesign>.Default);
|
|
hash.Add(Extensions, XmlElementArrayStringEqualityComparer.Default);
|
|
hash.Add(TargetNamespace);
|
|
hash.Add(TargetVersion);
|
|
hash.Add(TargetPublicationDate);
|
|
hash.Add(TargetXmlNamespace);
|
|
hash.Add(DefaultLocale);
|
|
return hash.ToHashCode();
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public static bool operator ==(ModelDesign left, ModelDesign right)
|
|
{
|
|
return EqualityComparer<ModelDesign>.Default.Equals(left, right);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public static bool operator !=(ModelDesign left, ModelDesign right)
|
|
{
|
|
return !(left == right);
|
|
}
|
|
}
|
|
|
|
public partial class LocalizedText : IEquatable<LocalizedText>
|
|
{
|
|
/// <summary>
|
|
/// Text is autogenerated
|
|
/// </summary>
|
|
[XmlIgnore]
|
|
public bool IsAutogenerated { get; set; }
|
|
|
|
/// <inheritdoc/>
|
|
public override bool Equals(object obj)
|
|
{
|
|
return obj is LocalizedText other && Equals(other);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public bool Equals(LocalizedText other)
|
|
{
|
|
if (ReferenceEquals(this, other))
|
|
{
|
|
return true;
|
|
}
|
|
return other is not null &&
|
|
Key == other.Key &&
|
|
DoNotIgnore == other.DoNotIgnore &&
|
|
Value == other.Value &&
|
|
IsAutogenerated == other.IsAutogenerated;
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public override int GetHashCode()
|
|
{
|
|
return HashCode.Combine(Key, DoNotIgnore, Value, IsAutogenerated);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public static bool operator ==(LocalizedText left, LocalizedText right)
|
|
{
|
|
return EqualityComparer<LocalizedText>.Default.Equals(left, right);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public static bool operator !=(LocalizedText left, LocalizedText right)
|
|
{
|
|
return !(left == right);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Hierarchy node information
|
|
/// </summary>
|
|
public record class HierarchyNode
|
|
{
|
|
/// <summary>
|
|
/// Relative path
|
|
/// </summary>
|
|
public string RelativePath { get; set; }
|
|
|
|
/// <summary>
|
|
/// Instance
|
|
/// </summary>
|
|
public NodeDesign Instance { get; set; }
|
|
|
|
/// <summary>
|
|
/// Overridden nodes
|
|
/// </summary>
|
|
public List<NodeDesign> OverriddenNodes { get; set; }
|
|
|
|
/// <summary>
|
|
/// Explicitly defined
|
|
/// </summary>
|
|
public bool ExplicitlyDefined { get; set; }
|
|
|
|
/// <summary>
|
|
/// Ad hoc instance
|
|
/// </summary>
|
|
public bool AdHocInstance { get; set; }
|
|
|
|
/// <summary>
|
|
/// Static value
|
|
/// </summary>
|
|
public bool StaticValue { get; set; }
|
|
|
|
/// <summary>
|
|
/// Inherited
|
|
/// </summary>
|
|
public bool Inherited { get; set; }
|
|
|
|
/// <summary>
|
|
/// The modelling rule defined on the type definition for this node,
|
|
/// before any instance-level overrides are applied.
|
|
/// </summary>
|
|
public ModellingRule? TypeDefinitionModellingRule { get; set; }
|
|
|
|
/// <summary>
|
|
/// Identifier
|
|
/// </summary>
|
|
public object Identifier { get; set; }
|
|
|
|
/// <summary>
|
|
/// Returns the string representation of the object.
|
|
/// </summary>
|
|
public override string ToString()
|
|
{
|
|
if (Instance != null && Instance.SymbolicId != null)
|
|
{
|
|
return CoreUtils.Format("{0}={1}", RelativePath, Instance.SymbolicId.Name);
|
|
}
|
|
return RelativePath;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Reference between hierarchy nodes
|
|
/// </summary>
|
|
public record class HierarchyReference
|
|
{
|
|
/// <summary>
|
|
/// Source path
|
|
/// </summary>
|
|
public string SourcePath { get; set; }
|
|
|
|
/// <summary>
|
|
/// reference type
|
|
/// </summary>
|
|
public XmlQualifiedName ReferenceType { get; set; }
|
|
|
|
/// <summary>
|
|
/// Is inverse
|
|
/// </summary>
|
|
public bool IsInverse { get; set; }
|
|
|
|
/// <summary>
|
|
/// Target path
|
|
/// </summary>
|
|
public string TargetPath { get; set; }
|
|
|
|
/// <summary>
|
|
/// Target id
|
|
/// </summary>
|
|
public XmlQualifiedName TargetId { get; set; }
|
|
|
|
/// <summary>
|
|
/// Defined on type
|
|
/// </summary>
|
|
public bool DefinedOnType { get; set; }
|
|
|
|
/// <summary>
|
|
/// Returns the string representation of the object.
|
|
/// </summary>
|
|
public override string ToString()
|
|
{
|
|
if (TargetId != null)
|
|
{
|
|
return CoreUtils.Format("{0} => {1}", SourcePath, TargetId.Name);
|
|
}
|
|
|
|
return CoreUtils.Format("{0} => {1}", SourcePath, TargetPath);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Hierarchy information for a type or instance.
|
|
/// </summary>
|
|
public record class Hierarchy
|
|
{
|
|
/// <summary>
|
|
/// Type
|
|
/// </summary>
|
|
public TypeDesign Type { get; set; }
|
|
|
|
/// <summary>
|
|
/// Nodes
|
|
/// </summary>
|
|
public Dictionary<string, HierarchyNode> Nodes { get; } = [];
|
|
|
|
/// <summary>
|
|
/// Node list
|
|
/// </summary>
|
|
public List<HierarchyNode> NodeList { get; } = [];
|
|
|
|
/// <summary>
|
|
/// References
|
|
/// </summary>
|
|
public List<HierarchyReference> References { get; set; } = [];
|
|
}
|
|
|
|
/// <summary>
|
|
/// A class that stores the model design for a Node.
|
|
/// </summary>
|
|
public partial class NodeDesign : IFormattable, IEquatable<NodeDesign>
|
|
{
|
|
/// <summary>
|
|
/// Parent node
|
|
/// </summary>
|
|
[XmlIgnore]
|
|
public NodeDesign Parent { get; set; }
|
|
|
|
/// <summary>
|
|
/// Has children
|
|
/// </summary>
|
|
[XmlIgnore]
|
|
public bool HasChildren { get; set; }
|
|
|
|
/// <summary>
|
|
/// Has references
|
|
/// </summary>
|
|
[XmlIgnore]
|
|
public bool HasReferences { get; set; }
|
|
|
|
/// <summary>
|
|
/// Hierarchy
|
|
/// </summary>
|
|
[XmlIgnore]
|
|
#pragma warning disable CA2235 // Mark all non-serializable fields
|
|
public Hierarchy Hierarchy { get; set; }
|
|
#pragma warning restore CA2235 // Mark all non-serializable fields
|
|
|
|
/// <summary>
|
|
/// Returns the string representation of the object.
|
|
/// </summary>
|
|
public override string ToString()
|
|
{
|
|
return ToString(null, null);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns the string representation of the object.
|
|
/// </summary>
|
|
/// <exception cref="FormatException"></exception>
|
|
public string ToString(string format, IFormatProvider formatProvider)
|
|
{
|
|
if (format == null)
|
|
{
|
|
if (SymbolicName != null)
|
|
{
|
|
return string.Format(formatProvider, "{0}", SymbolicName.Name);
|
|
}
|
|
|
|
return string.Format(formatProvider, "{0}", GetType().Name);
|
|
}
|
|
|
|
throw new FormatException(CoreUtils.Format("Invalid format string: '{0}'.", format));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Create symbol
|
|
/// </summary>
|
|
public static string CreateSymbolicId(XmlQualifiedName parentId, string childName)
|
|
{
|
|
if (parentId == null)
|
|
{
|
|
return childName;
|
|
}
|
|
|
|
return CreateSymbolicId(parentId.Name, childName);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Create symbol
|
|
/// </summary>
|
|
public static string CreateSymbolicId(string parentId, string childName)
|
|
{
|
|
if (string.IsNullOrEmpty(childName))
|
|
{
|
|
return parentId;
|
|
}
|
|
|
|
if (string.IsNullOrEmpty(parentId))
|
|
{
|
|
return childName;
|
|
}
|
|
|
|
return CoreUtils.Format("{0}{1}{2}", parentId, PathChar, childName);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public override bool Equals(object obj)
|
|
{
|
|
return obj is NodeDesign other && Equals(other);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public bool Equals(NodeDesign other)
|
|
{
|
|
if (ReferenceEquals(this, other))
|
|
{
|
|
return true;
|
|
}
|
|
return
|
|
other is not null &&
|
|
BrowseName == other.BrowseName &&
|
|
EqualityComparer<LocalizedText>.Default.Equals(DisplayName, other.DisplayName) &&
|
|
EqualityComparer<LocalizedText>.Default.Equals(Description, other.Description) &&
|
|
EqualityComparer<ListOfChildren>.Default.Equals(Children, other.Children) &&
|
|
ArrayEqualityComparer<Reference>.Default.Equals(References, other.References) &&
|
|
EqualityComparer<RolePermissionSet>.Default.Equals(RolePermissions, other.RolePermissions) &&
|
|
EqualityComparer<RolePermissionSet>.Default.Equals(DefaultRolePermissions, other.DefaultRolePermissions) &&
|
|
AccessRestrictions == other.AccessRestrictions &&
|
|
AccessRestrictionsSpecified == other.AccessRestrictionsSpecified &&
|
|
DefaultAccessRestrictions == other.DefaultAccessRestrictions &&
|
|
DefaultAccessRestrictionsSpecified == other.DefaultAccessRestrictionsSpecified &&
|
|
XmlElementArrayStringEqualityComparer.Default.Equals(Extensions, other.Extensions) &&
|
|
XmlQualifiedNameEqualityComparer.Default.Equals(SymbolicName, other.SymbolicName) &&
|
|
XmlQualifiedNameEqualityComparer.Default.Equals(SymbolicId, other.SymbolicId) &&
|
|
IsDeclaration == other.IsDeclaration &&
|
|
NumericId == other.NumericId &&
|
|
NumericIdSpecified == other.NumericIdSpecified &&
|
|
StringId == other.StringId &&
|
|
GuidId == other.GuidId &&
|
|
GuidIdSpecified == other.GuidIdSpecified &&
|
|
ArrayEqualityComparer<byte>.Default.Equals(OpaqueId, other.OpaqueId) &&
|
|
WriteAccess == other.WriteAccess &&
|
|
PartNo == other.PartNo &&
|
|
Category == other.Category &&
|
|
NotInAddressSpace == other.NotInAddressSpace &&
|
|
ReleaseStatus == other.ReleaseStatus &&
|
|
Purpose == other.Purpose &&
|
|
IsDynamic == other.IsDynamic;
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public override int GetHashCode()
|
|
{
|
|
var hash = new HashCode();
|
|
hash.Add(BrowseName);
|
|
hash.Add(DisplayName);
|
|
hash.Add(Description);
|
|
hash.Add(Children);
|
|
hash.Add(References, ArrayEqualityComparer<Reference>.Default);
|
|
hash.Add(RolePermissions);
|
|
hash.Add(DefaultRolePermissions);
|
|
hash.Add(AccessRestrictions);
|
|
hash.Add(AccessRestrictionsSpecified);
|
|
hash.Add(DefaultAccessRestrictions);
|
|
hash.Add(DefaultAccessRestrictionsSpecified);
|
|
hash.Add(Extensions, XmlElementArrayStringEqualityComparer.Default);
|
|
hash.Add(SymbolicName, XmlQualifiedNameEqualityComparer.Default);
|
|
hash.Add(SymbolicId, XmlQualifiedNameEqualityComparer.Default);
|
|
hash.Add(IsDeclaration);
|
|
hash.Add(NumericId);
|
|
hash.Add(NumericIdSpecified);
|
|
hash.Add(StringId);
|
|
hash.Add(GuidId);
|
|
hash.Add(GuidIdSpecified);
|
|
hash.Add(OpaqueId, ArrayEqualityComparer<byte>.Default);
|
|
hash.Add(WriteAccess);
|
|
hash.Add(PartNo);
|
|
hash.Add(Category);
|
|
hash.Add(NotInAddressSpace);
|
|
hash.Add(ReleaseStatus);
|
|
hash.Add(Purpose);
|
|
hash.Add(IsDynamic);
|
|
return hash.ToHashCode();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Path character to use when constructing symbolic ids.
|
|
/// </summary>
|
|
public const char PathChar = '_';
|
|
|
|
/// <summary>
|
|
/// Static array for splitting
|
|
/// </summary>
|
|
public static readonly char[] PathChars = [PathChar];
|
|
|
|
/// <inheritdoc/>
|
|
public static bool operator ==(NodeDesign left, NodeDesign right)
|
|
{
|
|
return EqualityComparer<NodeDesign>.Default.Equals(left, right);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public static bool operator !=(NodeDesign left, NodeDesign right)
|
|
{
|
|
return !(left == right);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// A class that stores the model design for a Variable.
|
|
/// </summary>
|
|
public partial class VariableDesign : IEquatable<VariableDesign>
|
|
{
|
|
/// <summary>
|
|
/// Decoded value
|
|
/// </summary>
|
|
[XmlIgnore]
|
|
public object DecodedValue { get; set; }
|
|
|
|
/// <summary>
|
|
/// The namespace table the namespace indexes inside
|
|
/// <see cref="DecodedValue"/> (NodeId, ExpandedNodeId, QualifiedName)
|
|
/// refer to - the table of the NodeSet the value was read from. Null
|
|
/// when the value was authored in a ModelDesign, whose indexes refer to
|
|
/// the design's own namespaces (OPC UA first).
|
|
/// </summary>
|
|
[XmlIgnore]
|
|
[field: NonSerialized]
|
|
public NamespaceTable DecodedValueNamespaceUris { get; set; }
|
|
|
|
/// <summary>
|
|
/// Data type node
|
|
/// </summary>
|
|
[XmlIgnore]
|
|
public DataTypeDesign DataTypeNode { get; set; }
|
|
|
|
/// <summary>
|
|
/// The verbatim OPC UA AccessLevel bitmask imported from a
|
|
/// NodeSet2 model. The ModelDesign <see cref="AccessLevel"/>
|
|
/// enumeration cannot represent combinations such as
|
|
/// <c>CurrentRead | HistoryRead</c>, so the raw bits are carried
|
|
/// alongside it and preferred by code generation when present.
|
|
/// </summary>
|
|
[XmlIgnore]
|
|
public uint? RawAccessLevel { get; set; }
|
|
|
|
/// <summary>
|
|
/// The verbatim OPC UA UserAccessLevel bitmask imported from a
|
|
/// NodeSet2 model when the <c>UserAccessLevel</c> attribute is
|
|
/// explicitly present. When <c>null</c> the UserAccessLevel is
|
|
/// derived from the AccessLevel, matching the runtime importer.
|
|
/// </summary>
|
|
[XmlIgnore]
|
|
public uint? RawUserAccessLevel { get; set; }
|
|
|
|
/// <inheritdoc/>
|
|
public override bool Equals(object obj)
|
|
{
|
|
return obj is VariableDesign other && Equals(other);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public bool Equals(VariableDesign other)
|
|
{
|
|
if (ReferenceEquals(this, other))
|
|
{
|
|
return true;
|
|
}
|
|
return
|
|
other is not null &&
|
|
base.Equals(other) &&
|
|
XmlElementStringEqualityComparer.Default.Equals(DefaultValue, other.DefaultValue) &&
|
|
XmlQualifiedNameEqualityComparer.Default.Equals(DataType, other.DataType) &&
|
|
ValueRank == other.ValueRank &&
|
|
ArrayDimensions == other.ArrayDimensions &&
|
|
AccessLevel == other.AccessLevel &&
|
|
AccessLevelSpecified == other.AccessLevelSpecified &&
|
|
RawAccessLevel == other.RawAccessLevel &&
|
|
RawUserAccessLevel == other.RawUserAccessLevel &&
|
|
InstanceAccessLevel == other.InstanceAccessLevel &&
|
|
InstanceAccessLevelSpecified == other.InstanceAccessLevelSpecified &&
|
|
MinimumSamplingInterval == other.MinimumSamplingInterval &&
|
|
MinimumSamplingIntervalSpecified == other.MinimumSamplingIntervalSpecified &&
|
|
Historizing == other.Historizing &&
|
|
HistorizingSpecified == other.HistorizingSpecified;
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public override int GetHashCode()
|
|
{
|
|
var hash = new HashCode();
|
|
hash.Add(base.GetHashCode());
|
|
hash.Add(DefaultValue, XmlElementStringEqualityComparer.Default);
|
|
hash.Add(DataType, XmlQualifiedNameEqualityComparer.Default);
|
|
hash.Add(ValueRank);
|
|
hash.Add(ArrayDimensions);
|
|
hash.Add(AccessLevel);
|
|
hash.Add(AccessLevelSpecified);
|
|
hash.Add(RawAccessLevel);
|
|
hash.Add(RawUserAccessLevel);
|
|
hash.Add(InstanceAccessLevel);
|
|
hash.Add(InstanceAccessLevelSpecified);
|
|
hash.Add(MinimumSamplingInterval);
|
|
hash.Add(MinimumSamplingIntervalSpecified);
|
|
hash.Add(Historizing);
|
|
hash.Add(HistorizingSpecified);
|
|
return hash.ToHashCode();
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public static bool operator ==(VariableDesign left, VariableDesign right)
|
|
{
|
|
return EqualityComparer<VariableDesign>.Default.Equals(left, right);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public static bool operator !=(VariableDesign left, VariableDesign right)
|
|
{
|
|
return !(left == right);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// A class that stores the model design for a VariableType.
|
|
/// </summary>
|
|
public partial class VariableTypeDesign : IEquatable<VariableTypeDesign>
|
|
{
|
|
/// <summary>
|
|
/// Decoded value
|
|
/// </summary>
|
|
[XmlIgnore]
|
|
public object DecodedValue { get; set; }
|
|
|
|
/// <summary>
|
|
/// The namespace table the namespace indexes inside
|
|
/// <see cref="DecodedValue"/> refer to. See
|
|
/// <see cref="VariableDesign.DecodedValueNamespaceUris"/>.
|
|
/// </summary>
|
|
[XmlIgnore]
|
|
[field: NonSerialized]
|
|
public NamespaceTable DecodedValueNamespaceUris { get; set; }
|
|
|
|
/// <summary>
|
|
/// Data type node
|
|
/// </summary>
|
|
[XmlIgnore]
|
|
public DataTypeDesign DataTypeNode { get; set; }
|
|
|
|
/// <inheritdoc/>
|
|
public override bool Equals(object obj)
|
|
{
|
|
return obj is VariableTypeDesign other && Equals(other);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public bool Equals(VariableTypeDesign other)
|
|
{
|
|
if (ReferenceEquals(this, other))
|
|
{
|
|
return true;
|
|
}
|
|
return
|
|
other is not null &&
|
|
base.Equals(other) &&
|
|
XmlElementStringEqualityComparer.Default.Equals(DefaultValue, other.DefaultValue) &&
|
|
XmlQualifiedNameEqualityComparer.Default.Equals(DataType, other.DataType) &&
|
|
ValueRank == other.ValueRank &&
|
|
ValueRankSpecified == other.ValueRankSpecified &&
|
|
ArrayDimensions == other.ArrayDimensions &&
|
|
AccessLevel == other.AccessLevel &&
|
|
AccessLevelSpecified == other.AccessLevelSpecified &&
|
|
MinimumSamplingInterval == other.MinimumSamplingInterval &&
|
|
MinimumSamplingIntervalSpecified == other.MinimumSamplingIntervalSpecified &&
|
|
Historizing == other.Historizing &&
|
|
HistorizingSpecified == other.HistorizingSpecified &&
|
|
ExposesItsChildren == other.ExposesItsChildren;
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public override int GetHashCode()
|
|
{
|
|
var hash = new HashCode();
|
|
hash.Add(base.GetHashCode());
|
|
hash.Add(DefaultValue, XmlElementStringEqualityComparer.Default);
|
|
hash.Add(DataType, XmlQualifiedNameEqualityComparer.Default);
|
|
hash.Add(ValueRank);
|
|
hash.Add(ValueRankSpecified);
|
|
hash.Add(ArrayDimensions);
|
|
hash.Add(AccessLevel);
|
|
hash.Add(AccessLevelSpecified);
|
|
hash.Add(MinimumSamplingInterval);
|
|
hash.Add(MinimumSamplingIntervalSpecified);
|
|
hash.Add(Historizing);
|
|
hash.Add(HistorizingSpecified);
|
|
hash.Add(ExposesItsChildren);
|
|
return hash.ToHashCode();
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public static bool operator ==(VariableTypeDesign left, VariableTypeDesign right)
|
|
{
|
|
return EqualityComparer<VariableTypeDesign>.Default.Equals(left, right);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public static bool operator !=(VariableTypeDesign left, VariableTypeDesign right)
|
|
{
|
|
return !(left == right);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// A class that stores the model design for a Method.
|
|
/// </summary>
|
|
public partial class MethodDesign : IEquatable<MethodDesign>
|
|
{
|
|
/// <summary>
|
|
/// Has arguments
|
|
/// </summary>
|
|
[XmlIgnore]
|
|
public bool HasArguments { get; set; }
|
|
|
|
/// <summary>
|
|
/// Method type node
|
|
/// </summary>
|
|
[XmlIgnore]
|
|
public MethodDesign MethodType { get; set; }
|
|
|
|
/// <summary>
|
|
/// Method declaration node
|
|
/// </summary>
|
|
[XmlIgnore]
|
|
public MethodDesign MethodDeclarationNode { get; set; }
|
|
|
|
/// <inheritdoc/>
|
|
public override bool Equals(object obj)
|
|
{
|
|
return obj is MethodDesign other && Equals(other);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public bool Equals(MethodDesign other)
|
|
{
|
|
if (ReferenceEquals(this, other))
|
|
{
|
|
return true;
|
|
}
|
|
return
|
|
other is not null &&
|
|
base.Equals(other) &&
|
|
ArrayEqualityComparer<Parameter>.Default.Equals(InputArguments, other.InputArguments) &&
|
|
ArrayEqualityComparer<Parameter>.Default.Equals(OutputArguments, other.OutputArguments) &&
|
|
NonExecutable == other.NonExecutable &&
|
|
NonExecutableSpecified == other.NonExecutableSpecified;
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public override int GetHashCode()
|
|
{
|
|
var hash = new HashCode();
|
|
hash.Add(base.GetHashCode());
|
|
hash.Add(InputArguments, ArrayEqualityComparer<Parameter>.Default);
|
|
hash.Add(OutputArguments, ArrayEqualityComparer<Parameter>.Default);
|
|
hash.Add(NonExecutable);
|
|
hash.Add(NonExecutableSpecified);
|
|
return hash.ToHashCode();
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public static bool operator ==(MethodDesign left, MethodDesign right)
|
|
{
|
|
return EqualityComparer<MethodDesign>.Default.Equals(left, right);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public static bool operator !=(MethodDesign left, MethodDesign right)
|
|
{
|
|
return !(left == right);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// A class that stores the model design for a Type.
|
|
/// </summary>
|
|
public partial class TypeDesign : IEquatable<TypeDesign>
|
|
{
|
|
/// <summary>
|
|
/// Base type node
|
|
/// </summary>
|
|
[XmlIgnore]
|
|
public TypeDesign BaseTypeNode { get; set; }
|
|
|
|
/// <summary>
|
|
/// True if the type is excluded from generation (for example a
|
|
/// Draft type with the Draft exclusion), so no state class is
|
|
/// emitted for it. Set by the validator.
|
|
/// </summary>
|
|
[XmlIgnore]
|
|
public bool IsExcludedFromGeneration { get; set; }
|
|
|
|
/// <summary>
|
|
/// Deep copy the type design.
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public TypeDesign Copy()
|
|
{
|
|
return (TypeDesign)MemberwiseClone();
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public override bool Equals(object obj)
|
|
{
|
|
return obj is TypeDesign other && Equals(other);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public bool Equals(TypeDesign other)
|
|
{
|
|
if (ReferenceEquals(this, other))
|
|
{
|
|
return true;
|
|
}
|
|
return
|
|
other is not null &&
|
|
base.Equals(other) &&
|
|
ClassName == other.ClassName &&
|
|
XmlQualifiedNameEqualityComparer.Default.Equals(BaseType, other.BaseType) &&
|
|
IsAbstract == other.IsAbstract &&
|
|
NoClassGeneration == other.NoClassGeneration &&
|
|
EqualityComparer<TypeDesign>.Default.Equals(BaseTypeNode, other.BaseTypeNode);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public override int GetHashCode()
|
|
{
|
|
var hash = new HashCode();
|
|
hash.Add(base.GetHashCode());
|
|
hash.Add(ClassName);
|
|
hash.Add(BaseType, XmlQualifiedNameEqualityComparer.Default);
|
|
hash.Add(IsAbstract);
|
|
hash.Add(NoClassGeneration);
|
|
hash.Add(BaseTypeNode);
|
|
return hash.ToHashCode();
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public static bool operator ==(TypeDesign left, TypeDesign right)
|
|
{
|
|
return EqualityComparer<TypeDesign>.Default.Equals(left, right);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public static bool operator !=(TypeDesign left, TypeDesign right)
|
|
{
|
|
return !(left == right);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// A class that stores the model design for a Type.
|
|
/// </summary>
|
|
public partial class InstanceDesign : IEquatable<InstanceDesign>
|
|
{
|
|
/// <summary>
|
|
/// Type definition node
|
|
/// </summary>
|
|
[XmlIgnore]
|
|
public TypeDesign TypeDefinitionNode { get; set; }
|
|
|
|
/// <summary>
|
|
/// Overidden node
|
|
/// </summary>
|
|
[XmlIgnore]
|
|
public InstanceDesign OveriddenNode { get; set; }
|
|
|
|
/// <summary>
|
|
/// Identifier required
|
|
/// </summary>
|
|
[XmlIgnore]
|
|
public bool IdentifierRequired { get; set; }
|
|
|
|
/// <summary>
|
|
/// Deep copy the instance design.
|
|
/// </summary>
|
|
public InstanceDesign Copy()
|
|
{
|
|
return (InstanceDesign)MemberwiseClone();
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public override bool Equals(object obj)
|
|
{
|
|
return obj is InstanceDesign other && Equals(other);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public bool Equals(InstanceDesign other)
|
|
{
|
|
if (ReferenceEquals(this, other))
|
|
{
|
|
return true;
|
|
}
|
|
return
|
|
other is not null &&
|
|
base.Equals(other) &&
|
|
XmlQualifiedNameEqualityComparer.Default.Equals(ReferenceType, other.ReferenceType) &&
|
|
XmlQualifiedNameEqualityComparer.Default.Equals(Declaration, other.Declaration) &&
|
|
XmlQualifiedNameEqualityComparer.Default.Equals(TypeDefinition, other.TypeDefinition) &&
|
|
ModellingRule == other.ModellingRule &&
|
|
ModellingRuleSpecified == other.ModellingRuleSpecified &&
|
|
MinCardinality == other.MinCardinality &&
|
|
MaxCardinality == other.MaxCardinality &&
|
|
PreserveDefaultAttributes == other.PreserveDefaultAttributes &&
|
|
DesignToolOnly == other.DesignToolOnly &&
|
|
XmlQualifiedNameEqualityComparer.Default.Equals(
|
|
TypeDefinitionNode?.SymbolicId,
|
|
other.TypeDefinitionNode?.SymbolicId) &&
|
|
XmlQualifiedNameEqualityComparer.Default.Equals(
|
|
OveriddenNode?.SymbolicId,
|
|
other.OveriddenNode?.SymbolicId) &&
|
|
IdentifierRequired == other.IdentifierRequired;
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public override int GetHashCode()
|
|
{
|
|
var hash = new HashCode();
|
|
hash.Add(base.GetHashCode());
|
|
hash.Add(ReferenceType, XmlQualifiedNameEqualityComparer.Default);
|
|
hash.Add(Declaration, XmlQualifiedNameEqualityComparer.Default);
|
|
hash.Add(TypeDefinition, XmlQualifiedNameEqualityComparer.Default);
|
|
hash.Add(ModellingRule);
|
|
hash.Add(ModellingRuleSpecified);
|
|
hash.Add(MinCardinality);
|
|
hash.Add(MaxCardinality);
|
|
hash.Add(PreserveDefaultAttributes);
|
|
hash.Add(DesignToolOnly);
|
|
hash.Add(TypeDefinitionNode?.SymbolicId, XmlQualifiedNameEqualityComparer.Default);
|
|
hash.Add(OveriddenNode?.SymbolicId, XmlQualifiedNameEqualityComparer.Default);
|
|
hash.Add(IdentifierRequired);
|
|
return hash.ToHashCode();
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public static bool operator ==(InstanceDesign left, InstanceDesign right)
|
|
{
|
|
return EqualityComparer<InstanceDesign>.Default.Equals(left, right);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public static bool operator !=(InstanceDesign left, InstanceDesign right)
|
|
{
|
|
return !(left == right);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// A class that stores a reference between nodes.
|
|
/// </summary>
|
|
public partial class Reference : IEquatable<Reference>
|
|
{
|
|
/// <summary>
|
|
/// Source node
|
|
/// </summary>
|
|
[XmlIgnore]
|
|
public NodeDesign SourceNode { get; set; }
|
|
|
|
/// <summary>
|
|
/// Source relative path
|
|
/// </summary>
|
|
[XmlIgnore]
|
|
#pragma warning disable CA2235 // Mark all non-serializable fields
|
|
public RelativePath SourceRelativePath { get; set; }
|
|
#pragma warning restore CA2235 // Mark all non-serializable fields
|
|
|
|
/// <summary>
|
|
/// Target node
|
|
/// </summary>
|
|
[XmlIgnore]
|
|
public NodeDesign TargetNode { get; set; }
|
|
|
|
/// <summary>
|
|
/// Target relative path
|
|
/// </summary>
|
|
[XmlIgnore]
|
|
#pragma warning disable CA2235 // Mark all non-serializable fields
|
|
public RelativePath TargetRelativePath { get; set; }
|
|
#pragma warning restore CA2235 // Mark all non-serializable fields
|
|
|
|
/// <inheritdoc/>
|
|
public override bool Equals(object obj)
|
|
{
|
|
return obj is Reference other && Equals(other);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public bool Equals(Reference other)
|
|
{
|
|
if (ReferenceEquals(this, other))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return
|
|
other is not null &&
|
|
XmlQualifiedNameEqualityComparer.Default.Equals(ReferenceType, other.ReferenceType) &&
|
|
XmlQualifiedNameEqualityComparer.Default.Equals(TargetId, other.TargetId) &&
|
|
IsInverse == other.IsInverse &&
|
|
IsOneWay == other.IsOneWay;
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public override int GetHashCode()
|
|
{
|
|
var hash = new HashCode();
|
|
hash.Add(ReferenceType, XmlQualifiedNameEqualityComparer.Default);
|
|
hash.Add(TargetId, XmlQualifiedNameEqualityComparer.Default);
|
|
hash.Add(IsInverse);
|
|
hash.Add(IsOneWay);
|
|
return hash.ToHashCode();
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public static bool operator ==(Reference left, Reference right)
|
|
{
|
|
return EqualityComparer<Reference>.Default.Equals(left, right);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public static bool operator !=(Reference left, Reference right)
|
|
{
|
|
return !(left == right);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// A class that stores a parameter for a node.
|
|
/// </summary>
|
|
public partial class Parameter : IEquatable<Parameter>
|
|
{
|
|
/// <summary>
|
|
/// Parent node
|
|
/// </summary>
|
|
[XmlIgnore]
|
|
public NodeDesign Parent { get; set; }
|
|
|
|
/// <summary>
|
|
/// Data type node
|
|
/// </summary>
|
|
[XmlIgnore]
|
|
public DataTypeDesign DataTypeNode { get; set; }
|
|
|
|
/// <summary>
|
|
/// Identifier is in name
|
|
/// </summary>
|
|
[XmlIgnore]
|
|
public bool IdentifierInName { get; set; }
|
|
|
|
/// <summary>
|
|
/// Is inherited
|
|
/// </summary>
|
|
[XmlIgnore]
|
|
public bool IsInherited { get; set; }
|
|
|
|
/// <summary>
|
|
/// The bit position an OptionSet field names (the EnumField Value,
|
|
/// OPC 10000-3 8.52), when known as a position rather than through
|
|
/// the <see cref="Identifier"/> mask. A subtype of the OptionSet
|
|
/// structure (8.40) has no upper bit, while the decimal Identifier
|
|
/// only holds masks up to bit 95; for a higher bit the Identifier
|
|
/// is 0 and this carries the bit. Read the bit with
|
|
/// <see cref="ModelDesignExtensions.TryGetOptionSetBit(Parameter, out int)"/>.
|
|
/// </summary>
|
|
[XmlIgnore]
|
|
public int? OptionSetBit { get; set; }
|
|
|
|
/// <inheritdoc/>
|
|
public override bool Equals(object obj)
|
|
{
|
|
return obj is Parameter other && Equals(other);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public bool Equals(Parameter other)
|
|
{
|
|
if (ReferenceEquals(this, other))
|
|
{
|
|
return true;
|
|
}
|
|
return
|
|
other is not null &&
|
|
EqualityComparer<LocalizedText>.Default.Equals(Description, other.Description) &&
|
|
EqualityComparer<System.Xml.XmlElement>.Default.Equals(DefaultValue, other.DefaultValue) &&
|
|
EqualityComparer<LocalizedText>.Default.Equals(DisplayName, other.DisplayName) &&
|
|
Name == other.Name &&
|
|
Identifier == other.Identifier &&
|
|
IdentifierSpecified == other.IdentifierSpecified &&
|
|
BitMask == other.BitMask &&
|
|
OptionSetBit == other.OptionSetBit &&
|
|
XmlQualifiedNameEqualityComparer.Default.Equals(DataType, other.DataType) &&
|
|
ValueRank == other.ValueRank &&
|
|
ArrayDimensions == other.ArrayDimensions &&
|
|
AllowSubTypes == other.AllowSubTypes &&
|
|
IsOptional == other.IsOptional &&
|
|
ReleaseStatus == other.ReleaseStatus;
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public override int GetHashCode()
|
|
{
|
|
var hash = new HashCode();
|
|
hash.Add(Description);
|
|
hash.Add(DefaultValue);
|
|
hash.Add(DisplayName);
|
|
hash.Add(Name);
|
|
hash.Add(Identifier);
|
|
hash.Add(IdentifierSpecified);
|
|
hash.Add(BitMask);
|
|
hash.Add(OptionSetBit);
|
|
hash.Add(DataType, XmlQualifiedNameEqualityComparer.Default);
|
|
hash.Add(ValueRank);
|
|
hash.Add(ArrayDimensions);
|
|
hash.Add(AllowSubTypes);
|
|
hash.Add(IsOptional);
|
|
hash.Add(ReleaseStatus);
|
|
return hash.ToHashCode();
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public static bool operator ==(Parameter left, Parameter right)
|
|
{
|
|
return EqualityComparer<Parameter>.Default.Equals(left, right);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public static bool operator !=(Parameter left, Parameter right)
|
|
{
|
|
return !(left == right);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// The set of basic data types
|
|
/// </summary>
|
|
public enum BasicDataType
|
|
{
|
|
/// <summary>
|
|
/// Boolean data type
|
|
/// </summary>
|
|
Boolean,
|
|
|
|
/// <summary>
|
|
/// Signed byte data type
|
|
/// </summary>
|
|
SByte,
|
|
|
|
/// <summary>
|
|
/// Unsigned byte data type
|
|
/// </summary>
|
|
Byte,
|
|
|
|
/// <summary>
|
|
/// 16-bit signed integer data type
|
|
/// </summary>
|
|
Int16,
|
|
|
|
/// <summary>
|
|
/// 16-bit unsigned integer data type
|
|
/// </summary>
|
|
UInt16,
|
|
|
|
/// <summary>
|
|
/// 32-bit signed integer data type
|
|
/// </summary>
|
|
Int32,
|
|
|
|
/// <summary>
|
|
/// 32-bit unsigned integer data type
|
|
/// </summary>
|
|
UInt32,
|
|
|
|
/// <summary>
|
|
/// 64-bit signed integer data type
|
|
/// </summary>
|
|
Int64,
|
|
|
|
/// <summary>
|
|
/// 64-bit unsigned integer data type
|
|
/// </summary>
|
|
UInt64,
|
|
|
|
/// <summary>
|
|
/// Single-precision floating point data type
|
|
/// </summary>
|
|
Float,
|
|
|
|
/// <summary>
|
|
/// Double-precision floating point data type
|
|
/// </summary>
|
|
Double,
|
|
|
|
/// <summary>
|
|
/// String data type
|
|
/// </summary>
|
|
String,
|
|
|
|
/// <summary>
|
|
/// DateTime data type
|
|
/// </summary>
|
|
DateTime,
|
|
|
|
/// <summary>
|
|
/// Globally unique identifier data type
|
|
/// </summary>
|
|
Guid,
|
|
|
|
/// <summary>
|
|
/// Byte string data type
|
|
/// </summary>
|
|
ByteString,
|
|
|
|
/// <summary>
|
|
/// XML element data type
|
|
/// </summary>
|
|
XmlElement,
|
|
|
|
/// <summary>
|
|
/// Node identifier data type
|
|
/// </summary>
|
|
NodeId,
|
|
|
|
/// <summary>
|
|
/// Expanded node identifier data type
|
|
/// </summary>
|
|
ExpandedNodeId,
|
|
|
|
/// <summary>
|
|
/// Status code data type
|
|
/// </summary>
|
|
StatusCode,
|
|
|
|
/// <summary>
|
|
/// Diagnostic information data type
|
|
/// </summary>
|
|
DiagnosticInfo,
|
|
|
|
/// <summary>
|
|
/// Qualified name data type
|
|
/// </summary>
|
|
QualifiedName,
|
|
|
|
/// <summary>
|
|
/// Localized text data type
|
|
/// </summary>
|
|
LocalizedText,
|
|
|
|
/// <summary>
|
|
/// Data value data type
|
|
/// </summary>
|
|
DataValue,
|
|
|
|
/// <summary>
|
|
/// Numeric data type
|
|
/// </summary>
|
|
Number,
|
|
|
|
/// <summary>
|
|
/// Integer data type
|
|
/// </summary>
|
|
Integer,
|
|
|
|
/// <summary>
|
|
/// Unsigned integer data type
|
|
/// </summary>
|
|
UInteger,
|
|
|
|
/// <summary>
|
|
/// Enumeration data type
|
|
/// </summary>
|
|
Enumeration,
|
|
|
|
/// <summary>
|
|
/// Structure data type
|
|
/// </summary>
|
|
Structure,
|
|
|
|
/// <summary>
|
|
/// Base data type
|
|
/// </summary>
|
|
BaseDataType,
|
|
|
|
/// <summary>
|
|
/// User-defined data type
|
|
/// </summary>
|
|
UserDefined
|
|
}
|
|
|
|
/// <summary>
|
|
/// A class that stores the model design for a DataType.
|
|
/// </summary>
|
|
public partial class DataTypeDesign : IEquatable<DataTypeDesign>
|
|
{
|
|
/// <summary>
|
|
/// Has encodings
|
|
/// </summary>
|
|
[XmlIgnore]
|
|
public bool HasEncodings { get; set; }
|
|
|
|
/// <summary>
|
|
/// Has fields
|
|
/// </summary>
|
|
[XmlIgnore]
|
|
public bool HasFields { get; set; }
|
|
|
|
/// <summary>
|
|
/// Is structure
|
|
/// </summary>
|
|
[XmlIgnore]
|
|
public bool IsStructure { get; set; }
|
|
|
|
/// <summary>
|
|
/// Is enumeration
|
|
/// </summary>
|
|
[XmlIgnore]
|
|
public bool IsEnumeration { get; set; }
|
|
|
|
/// <summary>
|
|
/// Name of the service the data type belongs to
|
|
/// </summary>
|
|
[XmlIgnore]
|
|
public Service Service { get; set; }
|
|
|
|
/// <summary>
|
|
/// Is service response type
|
|
/// </summary>
|
|
[XmlIgnore]
|
|
public bool IsServiceResponse { get; set; }
|
|
|
|
/// <summary>
|
|
/// Built in data type
|
|
/// </summary>
|
|
[XmlIgnore]
|
|
public BasicDataType BasicDataType { get; set; }
|
|
|
|
/// <inheritdoc/>
|
|
public override bool Equals(object obj)
|
|
{
|
|
return obj is DataTypeDesign other && Equals(other);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public bool Equals(DataTypeDesign other)
|
|
{
|
|
if (ReferenceEquals(this, other))
|
|
{
|
|
return true;
|
|
}
|
|
return
|
|
other is not null &&
|
|
base.Equals(other) &&
|
|
ArrayEqualityComparer<Parameter>.Default.Equals(Fields, other.Fields) &&
|
|
ArrayEqualityComparer<EncodingDesign>.Default.Equals(Encodings, other.Encodings) &&
|
|
IsOptionSet == other.IsOptionSet &&
|
|
IsUnion == other.IsUnion &&
|
|
NoArraysAllowed == other.NoArraysAllowed &&
|
|
ForceEnumValues == other.ForceEnumValues &&
|
|
NoEncodings == other.NoEncodings &&
|
|
IsServiceResponse == other.IsServiceResponse &&
|
|
Service == other.Service;
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public override int GetHashCode()
|
|
{
|
|
var hash = new HashCode();
|
|
hash.Add(base.GetHashCode());
|
|
hash.Add(Fields, ArrayEqualityComparer<Parameter>.Default);
|
|
hash.Add(Encodings, ArrayEqualityComparer<EncodingDesign>.Default);
|
|
hash.Add(IsOptionSet);
|
|
hash.Add(IsUnion);
|
|
hash.Add(NoArraysAllowed);
|
|
hash.Add(ForceEnumValues);
|
|
hash.Add(NoEncodings);
|
|
hash.Add(Service);
|
|
hash.Add(IsServiceResponse);
|
|
return hash.ToHashCode();
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public static bool operator ==(DataTypeDesign left, DataTypeDesign right)
|
|
{
|
|
return EqualityComparer<DataTypeDesign>.Default.Equals(left, right);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public static bool operator !=(DataTypeDesign left, DataTypeDesign right)
|
|
{
|
|
return !(left == right);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Service descriptor
|
|
/// </summary>
|
|
[Serializable]
|
|
public sealed class Service : IEquatable<Service>
|
|
{
|
|
/// <summary>
|
|
/// Service category of the service the data type belongs to
|
|
/// </summary>
|
|
[XmlIgnore]
|
|
public ServiceCategory Category { get; init; }
|
|
|
|
/// <summary>
|
|
/// Name of the service the data type belongs to
|
|
/// </summary>
|
|
[XmlIgnore]
|
|
public string Name { get; init; }
|
|
|
|
/// <summary>
|
|
/// Service request data type
|
|
/// </summary>
|
|
[XmlIgnore]
|
|
public DataTypeDesign Request { get; set; }
|
|
|
|
/// <summary>
|
|
/// Service response data type
|
|
/// </summary>
|
|
[XmlIgnore]
|
|
public DataTypeDesign Response { get; set; }
|
|
|
|
/// <inheritdoc/>
|
|
public override bool Equals(object obj)
|
|
{
|
|
return obj is Service other && Equals(other);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public bool Equals(Service other)
|
|
{
|
|
if (ReferenceEquals(this, other))
|
|
{
|
|
return true;
|
|
}
|
|
return
|
|
other is not null &&
|
|
Category == other.Category &&
|
|
Name == other.Name;
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public override int GetHashCode()
|
|
{
|
|
return HashCode.Combine(Category, Name);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public static bool operator ==(Service left, Service right)
|
|
{
|
|
return EqualityComparer<Service>.Default.Equals(left, right);
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public static bool operator !=(Service left, Service right)
|
|
{
|
|
return !(left == right);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Service
|
|
/// </summary>
|
|
public enum ServiceCategory
|
|
{
|
|
/// <summary>
|
|
/// Not part of a service
|
|
/// </summary>
|
|
None,
|
|
|
|
/// <summary>
|
|
/// Session
|
|
/// </summary>
|
|
Session,
|
|
|
|
/// <summary>
|
|
/// Secure channel
|
|
/// </summary>
|
|
SecureChannel,
|
|
|
|
/// <summary>
|
|
/// Discovery
|
|
/// </summary>
|
|
Discovery,
|
|
|
|
/// <summary>
|
|
/// Registration
|
|
/// </summary>
|
|
Registration,
|
|
|
|
/// <summary>
|
|
/// Attribute service set (Read, Write, HistoryRead, HistoryUpdate)
|
|
/// </summary>
|
|
Attribute,
|
|
|
|
/// <summary>
|
|
/// View service set (Browse, BrowseNext, TranslateBrowsePathsToNodeIds, RegisterNodes, UnregisterNodes)
|
|
/// </summary>
|
|
View,
|
|
|
|
/// <summary>
|
|
/// Method service set (Call)
|
|
/// </summary>
|
|
Method,
|
|
|
|
/// <summary>
|
|
/// MonitoredItem service set (CreateMonitoredItems, ModifyMonitoredItems, SetMonitoringMode, SetTriggering, DeleteMonitoredItems)
|
|
/// </summary>
|
|
MonitoredItem,
|
|
|
|
/// <summary>
|
|
/// Subscription service set (CreateSubscription, ModifySubscription, SetPublishingMode, Publish, Republish, TransferSubscriptions, DeleteSubscriptions)
|
|
/// </summary>
|
|
Subscription,
|
|
|
|
/// <summary>
|
|
/// Node management service set (AddNodes, AddReferences, DeleteNodes, DeleteReferences)
|
|
/// </summary>
|
|
NodeManagement,
|
|
|
|
/// <summary>
|
|
/// Query service set (QueryFirst, QueryNext)
|
|
/// </summary>
|
|
Query,
|
|
|
|
/// <summary>
|
|
/// Test
|
|
/// </summary>
|
|
Test
|
|
}
|
|
|
|
/// <summary>
|
|
/// Core standard versions
|
|
/// </summary>
|
|
public enum SpecificationVersion
|
|
{
|
|
/// <summary>
|
|
/// Version 1.03
|
|
/// </summary>
|
|
V103 = 103,
|
|
|
|
/// <summary>
|
|
/// Version 1.04
|
|
/// </summary>
|
|
V104 = 104,
|
|
|
|
/// <summary>
|
|
/// Version 1.05
|
|
/// </summary>
|
|
V105 = 105
|
|
}
|
|
}
|