This commit is contained in:
2026-04-17 14:55:32 -04:00
commit bc3ac1d4c9
18017 changed files with 4371742 additions and 0 deletions

View File

@@ -0,0 +1,131 @@
---
source_files:
- Common/DTS.Common.Serialization/Test/Module/IConvertable.cs
- Common/DTS.Common.Serialization/Test/Module/CalculatedChannel.cs
generated_at: "2026-04-16T03:40:25.931280+00:00"
model: "Qwen/Qwen3-Coder-Next-FP8"
schema_version: 1
sha256: "ac5cc711621ec54b"
---
# Module
## Documentation Page: `DTS.Serialization.Test.Module.IConvertable` and `DTS.Serialization.Test.Module.CalculatedChannel`
---
### 1. Purpose
This module provides serialization infrastructure and a concrete implementation for handling *calculated channels* in the DTS test data model. Specifically, the `IConvertable` interface defines a contract for objects that can be converted to/from the internal `Test.Module` serialization format, enabling interoperability with external or legacy serialization layers. The `CalculatedChannel` class implements this interface (via inheritance from `AnalogInputChannel`, which presumably implements `IConvertable`) and represents a derived channel whose values are computed from one or more source channels using a user-defined formula. It supports XML serialization/deserialization with custom attribute tagging and array-based source channel/module metadata.
---
### 2. Public Interface
#### `IConvertable` Interface (Nested in `Test.Module`)
- **`Module ToDtsSerializationTestModule(Test parentTest)`**
Converts the implementing object into a `Test.Module` instance. The `parentTest` parameter identifies the containing test context.
- **`void FromDtsSerializationTestModule(Module testModule, ReportErrors reportErrors)`**
Initializes the implementing object from a `Test.Module` instance. The `reportErrors` delegate is used to surface validation or parsing errors encountered during deserialization.
> **Note**: The interface is declared in `IConvertable.cs`, but its implementation is not shown in the provided source. The `CalculatedChannel` class inherits from `AnalogInputChannel`, which is assumed to implement `IConvertable`.
#### `CalculatedChannel` Class (Nested in `Test.Module`)
- **`CalculatedChannel(Module parentModule)`**
Constructor. Initializes a new `CalculatedChannel` instance with the given parent module.
- **`int[] SourceChannelNumber { get; set; }`**
Gets/sets the array of channel numbers from which this calculated channel derives its data.
- **`int[] SourceModuleNumber { get; set; }`**
Gets/sets the array of module numbers corresponding to each source channel.
- **`string[] SourceModuleSerialNumber { get; set; }`**
Gets/sets the array of serial numbers for the modules containing the source channels.
- **`string Calculation { get; set; }`**
Gets/sets the calculation expression (e.g., `"A + B * 2"`) applied to the source channels. Default: `"NONE"`.
- **`ulong T1 { get; set; }`**
Gets/sets a time parameter (likely for HIC calculations). Default: `0`.
- **`ulong T2 { get; set; }`**
Gets/sets a second time parameter (likely for HIC calculations). Default: `0`.
- **`double HIC { get; set; }`**
Gets/sets the Head Injury Criterion value (a derived metric). Default: `0.0`.
- **`double SampleRateHz { get; set; }`**
Gets/sets the sample rate (in Hz) for this calculated channel. Inherited from base class or set explicitly.
- **`override void WriteXml(XmlWriter writer)`**
Serializes the object to XML. Writes attributes for all public properties (including `SourceChannelNumber`, `SourceModuleNumber`, `SourceModuleSerialNumber`, `Calculation`, `SampleRateHz`, and conditionally `HIC`, `T1`, `T2`). Uses `AttributeExtractor<XmlSerializationTagAttribute>` to resolve XML tag names.
- **`override void ReadXml(XmlReader reader)`**
Deserializes the object from XML. Reads attributes using `PropertyAttributeDecoder<CalculatedChannel>`. Handles parsing of comma-separated integer arrays (`SourceChannelNumber`, `SourceModuleNumber`) and custom-delimited string arrays (`SourceModuleSerialNumber`, using `"_.-._"` as delimiter).
- **`static CalculatedChannel CreateInstance(Channel[] channels)`**
Factory method to create a `CalculatedChannel` from multiple source `Channel`s. Validates that the maximum sample rate is a multiple of each source channels sample rate. Copies all properties from the first channel using `TypeDescriptor`. Initializes `SourceChannelNumber`, `SourceModuleNumber`, and `SourceModuleSerialNumber` arrays from all input channels.
- **`static CalculatedChannel CreateInstance(Channel sourceChannel)`**
Factory method to create a `CalculatedChannel` from a single `Channel`. Sets `SourceChannelNumber`, `SourceModuleNumber`, and `SourceModuleSerialNumber` to single-element arrays derived from the source channel.
- **`override bool Equals(object obj)`**
Performs memberwise equality comparison with another `CalculatedChannel`. Compares: `ChannelId`, `SourceChannelNumber`, `ChannelDescriptionString`, `EngineeringUnits` (case-insensitive), `Calculation`, and `IsoCode`.
- **`override int GetHashCode()`**
Returns the hash code from the base class (no custom logic visible).
- **`override string ToString()`**
Returns `ChannelDescriptionString`.
---
### 3. Invariants
- **Array Length Consistency**: For `SourceChannelNumber`, `SourceModuleNumber`, and `SourceModuleSerialNumber`, all three arrays must have identical length. This is *enforced by convention* in `CreateInstance`, but not validated in `ReadXml`/`WriteXml`.
- **Sample Rate Compatibility**: In `CreateInstance(Channel[])`, the maximum sample rate among source channels must be an integer multiple of each source channels sample rate; otherwise, an `InvalidOperationException` is thrown.
- **Optional Fields**: `HIC`, `T1`, and `T2` are only serialized if `_HIC.IsValueInitialized` is `true`. This implies they are initialized conditionally (e.g., only when non-zero or explicitly set).
- **Default Values**: `Calculation` defaults to `"NONE"`, `SampleRateHz` defaults to `0`, numeric arrays default to `null`, and `HIC`/`T1`/`T2` default to `0`/`0U`/`0U`.
- **Serialization Format**:
- Integer arrays are comma-separated (e.g., `"1,2,3"`).
- String arrays use `"_.-._"` as a delimiter (e.g., `"SN1_.-._SN2_.-._SN3"`).
- XML attributes use tags defined by `[XmlSerializationTag(...)]` attributes.
---
### 4. Dependencies
#### Module Dependencies
- **`DTS.Common.Utilities.Xml.AttributeExtractor<T>`**
Used in `WriteXml` to extract XML tag names from attributes.
- **`DTS.Common.Utilities.Xml.PropertyAttributeDecoder<T>`**
Used in `ReadXml` to decode XML attributes into properties.
- **`DTS.Common.Utilities.Logging.APILogger`**
Used for logging in `WriteXml` and `ReadXml`.
- **`System.ComponentModel.TypeDescriptor`**
Used in `CreateInstance` to copy property values via reflection.
- **`DTS.Common.Classes.Sensors.LinearizationFormula`**
Used in `CreateInstance(Channel[])` to clone the linearization formula.
#### Inferred Dependencies
- `AnalogInputChannel` (base class of `CalculatedChannel`) must implement `IConvertable`, though its implementation is not shown here.
- `Test` and `Module` classes are nested containers (see namespace structure).
- `ReportErrors` delegate type is referenced in `IConvertable.FromDtsSerializationTestModule` but not defined in the provided source.
---
### 5. Gotchas
- **Array Delimiter Ambiguity**: The string array delimiter `"_.-._"` is not documented in comments and may conflict with legitimate serial numbers containing that substring. No escaping or quoting is applied.
- **Partial Initialization in `ReadXml`**: `HIC`, `T1`, and `T2` are only deserialized if the `HIC` attribute is present and non-whitespace. If only `T1`/`T2` are present, they will remain at default (`0`), potentially masking incomplete data.
- **Sample Rate Validation Only in Factory**: The sample rate divisibility check occurs *only* in `CreateInstance(Channel[])`, not during XML deserialization or direct property assignment. Invalid rates may be silently stored.
- **Property Copying via Reflection**: `CreateInstance` uses `TypeDescriptor.GetProperties` to copy properties. This may fail silently for properties that throw exceptions during `GetValue`/`SetValue` (exceptions are logged or swallowed).
- **No Deep Clone for `LinearizationFormula`**: The `LinearizationFormula` is cloned via constructor, but other reference-type properties (e.g., `LinearizationFormula` is the only one explicitly cloned) may be shared if not handled.
- **Case-Insensitive Comparison Only for `EngineeringUnits`**: The `Equals` method uses `StringComparison.OrdinalIgnoreCase` for `EngineeringUnits`, but other string properties (`Calculation`, `ChannelDescriptionString`, `IsoCode`) use case-sensitive comparison—this inconsistency may cause confusion.
- **`SourceModuleNumber` Not Populated in Factories**: In both `CreateInstance` overloads, `SourceModuleNumber` is initialized as an empty array (`moduleNumbers` is never populated), which is likely a bug.
> **Note**: The `ReportErrors` delegate signature and `AnalogInputChannel`s implementation of `IConvertable` are not visible in the provided source. Their behavior is inferred.