Grundsätzlich werden nur solche Datendeklarationen migriert, die auch tatsächlich im Code verwendet werden. Die Datendeklarationen, die strukturrelevant sind, werden getrennt in einer partial
Klasse mit dem Suffix localdata.cs
generiert. Alle übrigen Datendeklarationen landen in der für den Baustein generierten Klasse.
Für Datendeklaration welche als lokale Variablen erkannt werden, werden die Interop Klassen verwendet. Dazu wird aus den Klauseln zu der Datendeklaration eine Formatklasse erzeugt, welche als Argument für die entsprechende generische Klasse verwendet wird.
Alphanumerisch, 10 Stellen:
10 ZW-SUCH-PT PIC X(10).
private Alphanumeric<ZwSuchPtFormat> ZwSuchPt = new Alphanumeric<ZwSuchPtFormat>(); private sealed class ZwSuchPtFormat : AlphanumericFormat { public ZwSuchPtFormat() : base(length:10) {} }
Numerisch, 11 Stellen, USAGE COMP(binary):
10 L-MAX-ID PIC 9(11) COMP.
private Numeric<System.UInt64, LMaxIdFormat> LMaxId = new Numeric<System.UInt64, LMaxIdFormat>(); private sealed class LMaxIdFormat : NumericFormat<System.UInt64> { public LMaxIdFormat() : base(predecimals:11, usage:UsageEnum.Limited) {} }
Numerisch, 10 Vorkommastellen, 5 Nachkomastellen, mit Vorzeichen, USAGE COMP(binary):
10 L-MAX-BETRAG PIC S9(10)V9(5) COMP.
private Numeric<System.Double, LMaxBetragFormat> LMaxBetrag = new Numeric<System.Double, LMaxBetragFormat>(); private sealed class LMaxBetragFormat : NumericFormat<System.Double> { public LMaxBetragFormat() : base(predecimals:10, decimals:5, isSigned:true, usage:UsageEnum.Limited) {} }
Numerisch editiertes Feld mit 10 Vorkommastellen, 2 Nachkomastellen, sowie Dezimalpunkt und Tausender Trennzeichen:
10 L-ABRECHNUNGS-PME-X PIC Z.ZZZ.ZZZ.ZZ9,99.
private Numeric<System.Double, LAbrechnungsPmeXFormat> LAbrechnungsPmeX = new Numeric<System.Double, LAbrechnungsPmeXFormat>(); private sealed class LAbrechnungsPmeXFormat : NumericFormat<System.Double> { public LAbrechnungsPmeXFormat() : base(predecimals:10, decimals:2, usage:UsageEnum.Literal, displayFormat: "#,###,###,##0.00") {} }
Datendeklarationen welche als Datumsfelder erkannt werden, werden als System.DateTime
erzeugt:
10 L-VON-DATUM. 15 VON-JJJJ PIC 9(4). 15 FILLER PIC X(1). 15 VON-MM PIC 9(2). 15 FILLER PIC X(1). 15 VON-TT PIC 9(2).
private System.DateTime LVonDatum;
Für Datendeklarationen welche als enumerative Variable erkannt werden, wird ein System.Enum
erzeugt:
10 S-VEV-STORNIERT PIC X. 88 B-VEV-STORNIERT-NEIN VALUE 'N'. 88 B-VEV-STORNIERT-GEVO VALUE 'G'. 88 B-VEV-STORNIERT-JA VALUE 'J'.
private enum VevStorniertEnum { Nein, Gevo, Ja , }; private VevStorniertEnum SVevStorniert;
Wobei für bitweise Variablen der Enum
als Flagable
gekennzeichnet wird:
10 S-JNP-BER PIC 9. 88 B-JNP-BER-AB-NULL VALUE ZEROS. 88 B-JNP-BER-AB-INDBNDNLRZ VALUE 1. 88 B-JNP-BER-AB-ZWISU7 VALUE 2 1. 88 B-JNP-BER-AB-ZWISU8 VALUE 3 2 1. 88 B-JNP-BER-AB-JNETPRAE VALUE 4.
[Flags] private enum JnpBerEnum { AbNull = 0x00000001, // values ZEROS AbIndbndnlrz = 0x00000002, // values 1 AbZwisu7 = 0x00000004, // values 2, 1 AbZwisu8 = 0x00000008, // values 3, 2, 1 AbJnetprae = 0x00000010, // values 4 }; private JnpBerEnum SJnpBer;
Datendeklarationen welche als boolsche Variablen erkannt werden, werden als System.Boolean
erzeugt:
10 GEFUNDEN-MARKER PIC X. 88 B-NICHT-GEFUNDEN VALUE "N". 88 B-GEFUNDEN VALUE "J".
private System.Boolean BGefunden;
Wenn eine Datendeklaration als Konstante erkannt wird, wird dieser auch als const
mit seinem Initialwert erzeugt.
05 K-DIFF-MAX PIC S9(10)V9(5) COMP VALUE 0,50000.
private const System.Double KDiffMax = 0.50000;
10 K-MLD-GRP-SNPRAEMIE PIC X(10) VALUE 'SNPRAEMIE'.
private const System.String KMldGrpSnpraemie = @"SNPRAEMIE ";
Wenn Datendeklarationen als strukturrelevant erkannt werden, werden für die benötigte übergeordnete Gruppenstufen Klassen erzeugt, um die Struktur abzubilden. Diese Klassen basieren alle auf die Interop Klasse DataGroup
.
Die generierte Klasse enthält für alle in der Gruppestufe benötigte Datendeklarationen eine property
die die Methoden GetMember
und SetMember
der Basisklasse aufrufen.
Für die Umsetzung des LENGTH OF-Abfrage wird zusätzlich ein static property
mit dem Namen Size
erzeugt, welches die Methode SizeOf
der Basisklasse aufruft.
Für die Datendeklaration welche als Strukturwurzel erkannt werden, wird ein readonly property
erzeugt, was mit einer Instanz der zugehörige Klasse bestückt ist. Zusätzlich werden für alle referenzierte Datendeklarationen sog. Accessors erzeugt, damit diese im Code direkt angesprochen werden können, ohne diese über die jeweilige übergeordnete Gruppestufen qualifizieren zu müssen.
Datendeklaration, wobei die einzelne Felder und die übergeordnete Gruppenstufe im Code angesprochen werden:
05 HILFS-FELDER. 10 L-VSU-ID. 15 L-VSU-ID-TL1 PIC 9(10). 15 L-VSU-ID-TL2 PIC 9(05). ... * doppelte Einträge für VU + PRAE-TYP-K (BND) * auf inaktiv setzen, Einzelgänger sind OK. IF Z0AAMPM-PRIM-K-SNMPM-VPL-MPM-1 = L-VSU-ID AND Z0AAMPM-X50-PRAE-TYP-K = L-X50-PRAE-TYP-K THEN PERFORM M52-MPM-INAKTIV END-IF MOVE Z0AAMPM-Z01-PBS-ID TO L-VSU-ID-TL1 MOVE Z0AAMPM-Z01-PBS-VRS-NR TO L-VSU-ID-TL2
Generierte Code in localdata.cs
:
private LVsuIdGroup LVsuId { get; } = new LVsuIdGroup(); private sealed class LVsuIdGroup : DataGroup { public static int Size => SizeOf<LVsuIdGroup>(); public NumericLiteral<System.UInt64, LVsuIdTl1Format> LVsuIdTl1 { get => GetMember<NumericLiteral<System.UInt64, LVsuIdTl1Format>>(); set => SetMember(value); } public NumericLiteral<System.UInt32, LVsuIdTl2Format> LVsuIdTl2 { get => GetMember<NumericLiteral<System.UInt32, LVsuIdTl2Format>>(); set => SetMember(value); } } private NumericLiteral<System.UInt64, LVsuIdTl1Format> LVsuIdTl1 { get => LVsuId.LVsuIdTl1; set => LVsuId.LVsuIdTl1 = value; } private NumericLiteral<System.UInt32, LVsuIdTl2Format> LVsuIdTl2 { get => LVsuId.LVsuIdTl2; set => LVsuId.LVsuIdTl2 = value; }
Generierte C# Code wo die Felder angesprochen werden:
// doppelte Einträge für VU + PRAE-TYP-K (BND) // auf inaktiv setzen, Einzelgänger sind OK. if (Z0aampm.PrimKSnmpmVplMpm1 == LVsuId && Z0aampm.X50PraeTypK == LX50PraeTypK) { M52MpmInaktiv(); } LVsuIdTl1 = Z0aampm.Z01PbsId; LVsuIdTl2 = Z0aampm.Z01PbsVrsNr;
Datendeklaration die als anonym erkannt werden, aber strukturrelevant sind, werden bei der Generierung in der localdata.cs
berücksichtigt. Allerdings werden keine Accessors und setter
erzeugt.
10 K-MAX-VEV-ANZ-UEBERSCHRITTEN. 15 FILLER PIC X(20) VALUE 'Maximale Anzahl von '. 15 K-MAX-VEV-ANZ PIC 99. 15 FILLER PIC X(31) VALUE ' Verträgen wurde überschritten!'. ... MOVE L-VTL-MAX TO K-MAX-VEV-ANZ MOVE K-MAX-VEV-ANZ-UEBERSCHRITTEN TO L-OM-CND-ARG-1
Code in localdata.cs
private KMaxVevAnzUeberschrittenGroup KMaxVevAnzUeberschritten { get; } = new KMaxVevAnzUeberschrittenGroup(); private sealed class KMaxVevAnzUeberschrittenGroup : DataGroup { public static int Size => SizeOf<KMaxVevAnzUeberschrittenGroup>(); private AlphanumericFiller<Filler44Format> Filler44 => GetMember<AlphanumericFiller<Filler44Format>>(); public NumericLiteral<System.UInt16, KMaxVevAnzFormat> KMaxVevAnz { get => GetMember<NumericLiteral<System.UInt16, KMaxVevAnzFormat>>(); set => SetMember(value); } private AlphanumericFiller<Filler46Format> Filler46 => GetMember<AlphanumericFiller<Filler46Format>>(); } private NumericLiteral<System.UInt16, KMaxVevAnzFormat> KMaxVevAnz { get => KMaxVevAnzUeberschritten.KMaxVevAnz; set => KMaxVevAnzUeberschritten.KMaxVevAnz = value; }
Wenn eine Datendeklaration redefiniert wird, bzw. eine andere Datendeklaration redefiniert, werden diese Felder zusammen in eine (auf der Basisklasse DataGroup
basierende) Klasse generiert. Die property
für eine Datendeklaration welche ein andere Datendeklaration redefiniert, wird mit den RedefinesAttribute
versehen.
05 INDICES. ... 10 ZW-EBN-INDICES. ... 10 ZW-EBN-TAB REDEFINES ZW-EBN-INDICES. ...
Generierte Code in localdata.cs
:
private sealed class IndicesGroup : DataGroup { public static int Size => SizeOf<IndicesGroup>(); public ZwEbnIndicesGroup ZwEbnIndices => GetMember<ZwEbnIndicesGroup>(); [Redefines(nameof(ZwEbnIndices))] public ZwEbnTabGroup ZwEbnTab => GetMember<ZwEbnTabGroup>(); }
Wenn für eine Datendeklaration eine OCCURS Angabe verwendet wird, wird für dieses Feld die generische Klasse Array
verwendet. Im Falle einer Gruppenstufe werden für untergeordnete Felder Accessors generiert, die die Hilfsklassen verwenden.
Eine Gruppenstufe mit OCCURS:
10 PRAE-IND-TAB. 15 PRAE-IND-ROW OCCURS 54. 20 PRAE-X50-IND PIC S9(04) COMP. 20 K-PRAE-TYP-K PIC X(10).
Generierte Code in localdata.cs
:
private PraeIndTabGroup PraeIndTab { get; } = new PraeIndTabGroup(); private sealed class PraeIndTabGroup : DataGroup { [ArrayFormat(54)] public Array<PraeIndRowGroup> PraeIndRow => GetMember<Array<PraeIndRowGroup>>(); } private Array<PraeIndRowGroup> PraeIndRow => PraeIndTab.PraeIndRow; private sealed class PraeIndRowGroup : DataGroup { public Numeric<System.Int16, PraeX50IndFormat> PraeX50Ind { get => GetMember<Numeric<System.Int16, PraeX50IndFormat>>(); set => SetMember(value); } public Alphanumeric<KPraeTypKFormat> KPraeTypK { get => GetMember<Alphanumeric<KPraeTypKFormat>>(); set => SetMember(value); } } private Array<Numeric<System.Int16, PraeX50IndFormat>, PraeIndRowGroup> m_PraeX50Ind; private Array<Numeric<System.Int16, PraeX50IndFormat>, PraeIndRowGroup> PraeX50Ind => m_PraeX50Ind ?? (m_PraeX50Ind = new Array<Numeric<System.Int16, PraeX50IndFormat>, PraeIndRowGroup>(PraeIndTab.PraeIndRow, o => o.PraeX50Ind, (o, value) => o.PraeX50Ind = value)); private Array<Alphanumeric<KPraeTypKFormat>, PraeIndRowGroup> m_KPraeTypK; private Array<Alphanumeric<KPraeTypKFormat>, PraeIndRowGroup> KPraeTypK => m_KPraeTypK ?? (m_KPraeTypK = new Array<Alphanumeric<KPraeTypKFormat>, PraeIndRowGroup>(PraeIndTab.PraeIndRow, o => o.KPraeTypK, (o, value) => o.KPraeTypK = value));
2 Gruppenstufen mit OCCURS:
10 VEIN-EBN-ROW OCCURS 4. 15 VEIN-EBN-REC OCCURS 54. 20 VEIN-EBN-PRAE-K PIC S9(4) COMP.
Generierte Code in localdata.cs
:
private Array<VeinEbnRowGroup> VeinEbnRow { get; } = new Array<VeinEbnRowGroup>(4); private sealed class VeinEbnRowGroup : DataGroup { [ArrayFormat(54)] public Array<VeinEbnRecGroup> VeinEbnRec => GetMember<Array<VeinEbnRecGroup>>(); } private sealed class VeinEbnRecGroup : DataGroup { public Numeric<System.Int16, VeinEbnPraeKFormat> VeinEbnPraeK { get => GetMember<Numeric<System.Int16, VeinEbnPraeKFormat>>(); set => SetMember(value); } } private Array<Numeric<System.Int16, VeinEbnPraeKFormat>, VeinEbnRowGroup, VeinEbnRecGroup> m_VeinEbnPraeK; private Array<Numeric<System.Int16, VeinEbnPraeKFormat>, VeinEbnRowGroup, VeinEbnRecGroup> VeinEbnPraeK => m_VeinEbnPraeK ?? (m_VeinEbnPraeK = new Array<Numeric<System.Int16, VeinEbnPraeKFormat>, VeinEbnRowGroup, VeinEbnRecGroup>(VeinEbnRow, o => o.VeinEbnRec, o => o.VeinEbnPraeK, (o, value) => o.VeinEbnPraeK = value));
Hat eine Deklaration zusätzlich die Sortierungsangabe „Aufsteigend“ wird es als „Wörterbuch“ Dictionary erzeugt 1)
05 TAB-BZ-SATZ OCCURS 541 ASCENDING KEY IS TAB-BE
Dictionary<Numeric<System.UInt16, TabBeFormat>,TabBzSatzGroup> TabBzSatz = new();
Die Angabe der Verwendung Index Beziehungsweise die Angabe als Indexer bewirkt das die Deklaration als UInt32 erzeugt wird.2)
05 I-TAB USAGE INDEX.
05 TAB-BZ-SATZ OCCURS 541 INDEXED BY I-TAB
private System.UInt32 ITab = new System.UInt32();
Syntaktisch erkannt, aber von den Generatoren derzeit nicht unterstützt sind folgende Bestandteile: