Re: variable length fields for flexibility in subroutines




"Frank Swarbrick" <Frank.Swarbrick@xxxxxxxxxxxxxx> wrote in message
news:46A5CA8C.6F0F.0085.0@xxxxxxxxxxxxxxxxx
On 7/23/2007 at 9:22 PM, in message
<5gl9kaF3h1mj2U1@xxxxxxxxxxxxxxxxxx>,
Pete Dashwood<dashwood@xxxxxxxxxxxxxxxxxxxxxxxxx> wrote:

"Howard Brazee" <howard@xxxxxxxxxx> wrote in message
news:lb1aa353v90v36trefhjmf55caags7hc03@xxxxxxxxxx
On Mon, 23 Jul 2007 12:20:37 -0600, "Frank Swarbrick"
<Frank.Swarbrick@xxxxxxxxxxxxxx> wrote:

<snip>

I haven't used variable length records for decades - When I try what
you're doing, I figure my largest possible field is small enough that
I don't mind "wasting" memory.

Yep, fixed length works for me too. I use an "Interface Block" that is a

single 01 level.

It usually contains a return code, message, and any other parameters I
want
to pass, as subordinate levels.

Mine are normally 8K but that is just arbritrary, for compatiblity with
COM
BSTRINGs which must be 8K when handled by Fujitsu NetCOBOL.

I wouldn't touch OCCURS...DEPENDING with very long tongs and rubber
gloves,
especially not in the Linkage section...

I don't suppose you'd mind posting the format of this "Interface
Block"...?

Sure, no problem.

Let's just clear the decks, first, though... :-)

<DISCLAIMER>
The following post encompasses some controversial viewpoints. There are pros
and cons and the views expressed are arguable. However, I really don't care
whether people adopt what is here or not, so I won't be arguing it. What is
here works for me and has done for a considerable time.
If you can add anything positive, I'd really love to hear from you;
(especially with regard to translating COBOL data definitions into C#... I
don't pretend to expertise in this area, although I'm trying to acquire it).
There is C# code posted here as well as COBOL. Apparently that's offensive
to some here. I suggest you get over it, or skip this thread.
</DISCLAIMER>

What is an "Interface Block"?

This is just a structured block which uses COBOL's almost unique ability for
referencing fixed length fields. I've used them for years and they can be
extended easily and managed without trouble. Mine are usally 8K because it
just so happens that this is the length required to use the COM BSTRING
interface under Fujitsu OO COBOL, but they could be any size you like,
really. Pick something that is machine friendly...4,8, 16K

I usually start them off with a return code and a message, then the
parameters I'm interested in. Some of mine include an "action code" as well,
so they can do different things (e.g. the Interface Block to an access
module might specify an action code of "INSERT", "SELECT","UPDATE", or
"DELETE", along with a common buffer area, and any other parameters.

"Generalizing" parameterization is a very desirable thing, because the fewer
changes you make to interfaces, the fewer problems you are likely to
encounter later. I like parameters that are just...

LINKAGE SECTION.
01 passed-data pic x(8192).

then, before calling

....move progname-interface-block to passed data
call progname
using passed-data
....

Upon receiving...

move passed-data to ws-interface-block

Before returning...

move ws-interface-block to passed-data
....

Where progname-interface-block and ws-interface-block are the same COPYbook.

Now, yes, this does mean you have two copies of the interface block (one in
the calling program, and one in the called one) rather than just a single
shared copy as you would through linkage. For some people, this would not be
acceptable, but I find there are actually some benefits to it. (Interactive
debugging is greatly simplified for a start, but many people here apparently
dont use interactive debugging anyway, so for them it is academic. )

Another reason why this doesn't bother me is because the interface block is
usually much smaller than the full 8K allocated, so it isn't as wasteful as
you might think.

The major benefit is that you can change the interface block and extend it,
WITHOUT modifying the program linkage or interfacing.

This is particularly useful when dealing with nested COBOL programs.
(Fujitsu OO COBOL implements Class Methods through nested sub-programming)

(You need to recompile all programs using the block so they all have the
latest COPY, but you'd need to do that anyway if you did it through
Linkage.)

Here's an example:

000230 01 ws-interfaceBlock.
000240 12 ws-return pic x(5).
000250 88 ws-OK value '00000'. *> will contain SQLSTATE
if
000260 *> there
is a DB error
000270 12 ws-message pic x(256). *> will contain SQLMSG if
000280 *> there is a DB
error
000290 12 ws-buffer pic x(2048). *> holds free format address data
000300 *> this will be
formatted on return
000310 12 ws-breakdown.
000320 15 ws-streetNo pic x(20).
000330 15 ws-POBoxNo pic x(20).
000340 15 ws-RDNo pic x(8).
000350 15 ws-street pic x(150).
000360 15 ws-locality pic x(150).
000370 15 ws-city pic x(50).
000380 15 ws-lobby pic x(150).
000390 15 ws-postCode pic x(4).
000400 15 ws-addressType pic x(1).
000410 15 ws-streetSDX pic x(4).
000420 15 ws-localitySDX pic x(4).
000430 15 ws-lobbySDX pic x(4).
000440 15 ws-prologue pic x(100).
000450 12 ws-interface pic x.
000460 88 free-format-input value '1'.
000470 88 fixed-field-input value '2'.
000480 88 XML-input value '3'.
000490 12 ws-streetMatchFlag pic x(1).
000500 88 street-fuzzy value '0'.
000510 88 street-exact value '1'.
000520 12 ws-localityMatchFlag pic x(1).
000530 88 locality-fuzzy value '0'.
000540 88 locality-exact value '1'.
000550 12 ws-repeatLocalityFlag pic x(1).
000560 88 no-Locality value '1'.
000570 88 repeatLocality value '0'. *> used if
Locality = City
000580 12 ws-ignoreInvalidPostcodeFlag pic x(1).
000590 88 ignoreInvalidPostCode value '1'.
000600 88 reportInvalidPostCode value '0'. *>stops if Post
Code is invalid
000610 12 ws-foreignFlag pic x(1).
000620 88 foreign-address value '1'. *>stops if foreign
address detected
000630 88 NOT-foreign-address value '0'.
000631 12 ws-user-logon pic x(50).


Note there is no filler at the end.

To change the length of any of the fields, or to add new ones, is dead easy
in COBOL (it can become more problematic in other languages, see below)

Change the block, amend the affected programs that use the new fields,
recompile all programs using the new block... done. Exactly the same process
as you would use if you had the block defined in Linkage.

No messing with fillers, no counting bytes and setting the count into length
parameters (then finding it was wrong :-)).

It is straightforward and simple. Why mess with OCCURS ...DEPENDING...?

Here's where it gets a bit sticky...

I have programs written in C# that I want to use this same interface. I
thought about this for some time and tried to come up with a consistent way
I could manage this block in C# (the long term aim is to generate it
automatically from the COBOL definition, but I haven't done that yet.
Obviously, for any kind of generation to be possible, the C# implementation
needs to address the fields consistently...)

I need to be able to address each field in the block, and I need to be able
to address the block as a whole. I also need to be easily able to modify or
add fields to it.

(The hierarchic data definition of COBOL facilitates all of this, but it is
arguably more "difficult" in languages that don't define data that way.)

I don't know if the solution I finally arrived at is good, bad, or
indifferent, but it certainly works... :-) (Things with that attribute
usually get my vote...:-))

Every field is a property of the Class and can be accessed using GET and SET
methods.

An alternative I considered (and discarded) was to have an array with the
offset and length of every field, then dynamically build a SUBSTRING
statement every time I needed to access a field. This seemed too unwieldy.
The solution below gets compiled into a .DLL and so the source code is not
visible in any applications that use the interface; they just have a
reference to the Assembly. (Another example of Source code being
unimportant... :-))

Here's the C# Class that implements the above block...

using System;
using System.Collections.Generic;
using System.Text;

namespace AVSInterfaceBlockBuilder
{
public class AVSInterfaceBlockBuilder
{

private string _IntBlock;
// A read-write instance property:
public string IB
{
get
{
return _IntBlock;
}
set
{
_IntBlock = value;
_IntBlock = _IntBlock.PadRight(8192);
//reset all the subfields as the group field has been
changed...
_IBreturn = _IntBlock.Substring(0, 5);

_IBmessage = _IntBlock.Substring(_IBreturn.Length, 256);

_IBbuffer = _IntBlock.Substring(_IBreturn.Length +
_IBmessage.Length,
2048);

_IBstreetNo = _IntBlock.Substring(_IBreturn.Length +
_IBmessage.Length +
_IBbuffer.Length,
20);

_IBPOBoxNo = _IntBlock.Substring(_IBreturn.Length +
_IBmessage.Length +
_IBbuffer.Length +
_IBstreetNo.Length,
20);

_IBRDNo = _IntBlock.Substring(_IBreturn.Length +
_IBmessage.Length +
_IBbuffer.Length +
_IBstreetNo.Length +
_IBPOBoxNo.Length,
8);

_IBstreet = _IntBlock.Substring(_IBreturn.Length +
_IBmessage.Length +
_IBbuffer.Length +
_IBstreetNo.Length +
_IBPOBoxNo.Length +
_IBRDNo.Length,
150);

_IBlocality = _IntBlock.Substring(_IBreturn.Length +
_IBmessage.Length +
_IBbuffer.Length +
_IBstreetNo.Length +
_IBPOBoxNo.Length +
_IBRDNo.Length +
_IBstreet.Length,
150);

_IBcity = _IntBlock.Substring(_IBreturn.Length +
_IBmessage.Length +
_IBbuffer.Length +
_IBstreetNo.Length +
_IBPOBoxNo.Length +
_IBRDNo.Length +
_IBstreet.Length +
_IBlocality.Length,
50);

_IBlobby = _IntBlock.Substring(_IBreturn.Length +
_IBmessage.Length +
_IBbuffer.Length +
_IBstreetNo.Length +
_IBPOBoxNo.Length +
_IBRDNo.Length +
_IBstreet.Length +
_IBlocality.Length +
_IBcity.Length,
150);


_IBpostCode = _IntBlock.Substring(_IBreturn.Length +
_IBmessage.Length +
_IBbuffer.Length +
_IBstreetNo.Length +
_IBPOBoxNo.Length +
_IBRDNo.Length +
_IBstreet.Length +
_IBlocality.Length +
_IBcity.Length +
_IBlobby.Length,
4);

_IBaddressType = _IntBlock.Substring(_IBreturn.Length +
_IBmessage.Length +
_IBbuffer.Length +
_IBstreetNo.Length +
_IBPOBoxNo.Length +
_IBRDNo.Length +
_IBstreet.Length +
_IBlocality.Length +
_IBcity.Length +
_IBlobby.Length +
_IBpostCode.Length,
1);

_IBstreetSDX = _IntBlock.Substring(_IBreturn.Length +
_IBmessage.Length +
_IBbuffer.Length +
_IBstreetNo.Length +
_IBPOBoxNo.Length +
_IBRDNo.Length +
_IBstreet.Length +
_IBlocality.Length +
_IBcity.Length +
_IBlobby.Length +
_IBpostCode.Length +
_IBaddressType.Length,
4);

_IBlocalitySDX = _IntBlock.Substring(_IBreturn.Length +
_IBmessage.Length +
_IBbuffer.Length +
_IBstreetNo.Length +
_IBPOBoxNo.Length +
_IBRDNo.Length +
_IBstreet.Length +
_IBlocality.Length +
_IBcity.Length +
_IBlobby.Length +
_IBpostCode.Length +
_IBaddressType.Length +
_IBstreetSDX.Length,
4);

_IBlobbySDX = _IntBlock.Substring(_IBreturn.Length +
_IBmessage.Length +
_IBbuffer.Length +
_IBstreetNo.Length +
_IBPOBoxNo.Length +
_IBRDNo.Length +
_IBstreet.Length +
_IBlocality.Length +
_IBcity.Length +
_IBlobby.Length +
_IBpostCode.Length +
_IBaddressType.Length +
_IBstreetSDX.Length +
_IBlocalitySDX.Length,
4);

_IBprologue = _IntBlock.Substring(_IBreturn.Length +
_IBmessage.Length +
_IBbuffer.Length +
_IBstreetNo.Length +
_IBPOBoxNo.Length +
_IBRDNo.Length +
_IBstreet.Length +
_IBlocality.Length +
_IBcity.Length +
_IBlobby.Length +
_IBpostCode.Length +
_IBaddressType.Length +
_IBstreetSDX.Length +
_IBlocalitySDX.Length +
_IBlobbySDX.Length,
100);

_IBinterface = _IntBlock.Substring(_IBreturn.Length +
_IBmessage.Length +
_IBbuffer.Length +
_IBstreetNo.Length +
_IBPOBoxNo.Length +
_IBRDNo.Length +
_IBstreet.Length +
_IBlocality.Length +
_IBcity.Length +
_IBlobby.Length +
_IBpostCode.Length +
_IBaddressType.Length +
_IBstreetSDX.Length +
_IBlocalitySDX.Length +
_IBlobbySDX.Length +
_IBprologue.Length,
1);

_IBstreetMatchFlag = _IntBlock.Substring(_IBreturn.Length +
_IBmessage.Length +
_IBbuffer.Length +
_IBstreetNo.Length +
_IBPOBoxNo.Length +
_IBRDNo.Length +
_IBstreet.Length +
_IBlocality.Length +
_IBcity.Length +
_IBlobby.Length +
_IBpostCode.Length +
_IBaddressType.Length +
_IBstreetSDX.Length +
_IBlocalitySDX.Length +
_IBlobbySDX.Length +
_IBprologue.Length +
_IBinterface.Length,
1);

_IBlocalityMatchFlag = _IntBlock.Substring(_IBreturn.Length
+
_IBmessage.Length +
_IBbuffer.Length +
_IBstreetNo.Length +
_IBPOBoxNo.Length +
_IBRDNo.Length +
_IBstreet.Length +
_IBlocality.Length +
_IBcity.Length +
_IBlobby.Length +
_IBpostCode.Length +
_IBaddressType.Length +
_IBstreetSDX.Length +
_IBlocalitySDX.Length +
_IBlobbySDX.Length +
_IBprologue.Length +
_IBinterface.Length +
_IBstreetMatchFlag.Length,
1);

_IBrepeatLocalityFlag = _IntBlock.Substring(_IBreturn.Length
+
_IBmessage.Length +
_IBbuffer.Length +
_IBstreetNo.Length +
_IBPOBoxNo.Length +
_IBRDNo.Length +
_IBstreet.Length +
_IBlocality.Length +
_IBcity.Length +
_IBlobby.Length +
_IBpostCode.Length +
_IBaddressType.Length +
_IBstreetSDX.Length +
_IBlocalitySDX.Length +
_IBlobbySDX.Length +
_IBprologue.Length +
_IBinterface.Length +
_IBstreetMatchFlag.Length
+
_IBlocalityMatchFlag.Length,
1);

_IBignoreInvalidPostcodeFlag =
_IntBlock.Substring(_IBreturn.Length +
_IBmessage.Length +
_IBbuffer.Length +
_IBstreetNo.Length +
_IBPOBoxNo.Length +
_IBRDNo.Length +
_IBstreet.Length +
_IBlocality.Length +
_IBcity.Length +
_IBlobby.Length +
_IBpostCode.Length +
_IBaddressType.Length +
_IBstreetSDX.Length +
_IBlocalitySDX.Length +
_IBlobbySDX.Length +
_IBprologue.Length +
_IBinterface.Length +
_IBstreetMatchFlag.Length
+
_IBlocalityMatchFlag.Length
+
_IBrepeatLocalityFlag.Length,
1);

_IBforeignFlag = _IntBlock.Substring(_IBreturn.Length +
_IBmessage.Length +
_IBbuffer.Length +
_IBstreetNo.Length +
_IBPOBoxNo.Length +
_IBRDNo.Length +
_IBstreet.Length +
_IBlocality.Length +
_IBcity.Length +
_IBlobby.Length +
_IBpostCode.Length +
_IBaddressType.Length +
_IBstreetSDX.Length +
_IBlocalitySDX.Length +
_IBlobbySDX.Length +
_IBprologue.Length +
_IBinterface.Length +
_IBstreetMatchFlag.Length
+
_IBlocalityMatchFlag.Length
+
_IBrepeatLocalityFlag.Length
+
_IBignoreInvalidPostcodeFlag.Length,
1);

_IBLogonID = _IntBlock.Substring(_IBreturn.Length +
_IBmessage.Length +
_IBbuffer.Length +
_IBstreetNo.Length +
_IBPOBoxNo.Length +
_IBRDNo.Length +
_IBstreet.Length +
_IBlocality.Length +
_IBcity.Length +
_IBlobby.Length +
_IBpostCode.Length +
_IBaddressType.Length +
_IBstreetSDX.Length +
_IBlocalitySDX.Length +
_IBlobbySDX.Length +
_IBprologue.Length +
_IBinterface.Length +
_IBstreetMatchFlag.Length
+
_IBlocalityMatchFlag.Length
+
_IBrepeatLocalityFlag.Length
+
_IBignoreInvalidPostcodeFlag.Length
+
_IBforeignFlag.Length,
50);
}
}
private string _IBreturn;
// A read-write instance property:
public string IBreturn
{
get
{
return _IBreturn;
}
set
{
_IBreturn = value;
_IBreturn = _IBreturn.PadRight(5, char.Parse("0"));
_IntBlock = _IBreturn +
_IntBlock.Substring(_IBreturn.Length, _IntBlock.Length - 5);
}
}


private string _IBmessage;
// A read-write instance property:
public string IBmessage
{
get
{
return _IBmessage;
}
set
{
_IBmessage = value;
_IBmessage = _IBmessage.PadRight(256);
_IntBlock = _IntBlock.Substring(0, 5) + _IBmessage +
_IntBlock.Substring(261, _IntBlock.Length - 261);
}
}

private string _IBbuffer;
// A read-write instance property:
public string IBbuffer
{
get
{
return _IBbuffer;
}
set
{
_IBbuffer = value;
_IBbuffer = _IBbuffer.PadRight(2048);
_IntBlock = _IntBlock.Substring(0, 261) + _IBbuffer +
_IntBlock.Substring(2309, _IntBlock.Length - 2309);
}
}
private string _IBstreetNo;
// A read-write instance property:
public string IBstreetNo
{
get
{
return _IBstreetNo;
}
set
{
_IBstreetNo = value;
_IBstreetNo = _IBstreetNo.PadRight(20);
_IntBlock = _IntBlock.Substring(0, 2309) + _IBstreetNo +
_IntBlock.Substring(2329, _IntBlock.Length - 2329);
}
}
private string _IBPOBoxNo;
// A read-write instance property:
public string IBPOBox
{
get
{
return _IBPOBoxNo;
}
set
{
_IBPOBoxNo = value;
_IBPOBoxNo = _IBPOBoxNo.PadRight(20);
_IntBlock = _IntBlock.Substring(0, 2329) + _IBPOBoxNo +
_IntBlock.Substring(2349, _IntBlock.Length - 2349);
}
}

private string _IBRDNo;
// A read-write instance property:
public string IBRDNo
{
get
{
return _IBRDNo;
}
set
{
_IBRDNo = value;
_IBRDNo = _IBRDNo.PadRight(8);
_IntBlock = _IntBlock.Substring(0, 2349) + _IBRDNo +
_IntBlock.Substring(2357, _IntBlock.Length - 2357);
}
}

private string _IBstreet;
// A read-write instance property:
public string IBstreet
{
get
{
return _IBstreet;
}
set
{
_IBstreet = value;
_IBstreet = _IBstreet.PadRight(150);
_IntBlock = _IntBlock.Substring(0, 2357) + _IBstreet +
_IntBlock.Substring(2507, _IntBlock.Length - 2507);
}
}

private string _IBlocality;
// A read-write instance property:
public string IBlocality
{
get
{
return _IBlocality;
}
set
{
_IBlocality = value;
_IBlocality = _IBlocality.PadRight(150);
_IntBlock = _IntBlock.Substring(0, 2507) + _IBlocality +
_IntBlock.Substring(2657, _IntBlock.Length - 2657);
}
}

private string _IBcity;
// A read-write instance property:
public string IBcity
{
get
{
return _IBcity;
}
set
{
_IBcity = value;
_IBcity = _IBcity.PadRight(50);
_IntBlock = _IntBlock.Substring(0, 2657) + _IBcity +
_IntBlock.Substring(2707, _IntBlock.Length - 2707);
}
}

private string _IBlobby;
// A read-write instance property:
public string IBlobby
{
get
{
return _IBlobby;
}
set
{
_IBlobby = value;
_IBlobby = _IBlobby.PadRight(150);
_IntBlock = _IntBlock.Substring(0, 2707) + _IBlobby +
_IntBlock.Substring(2857, _IntBlock.Length - 2857);
}
}

private string _IBpostCode;
// A read-write instance property:
public string IBpostCode
{
get
{
return _IBpostCode;
}
set
{
_IBpostCode = value;
_IBpostCode = _IBpostCode.PadRight(4);
_IntBlock = _IntBlock.Substring(0, 2857) + _IBpostCode +
_IntBlock.Substring(2861, _IntBlock.Length - 2861);
}
}

private string _IBaddressType;
// A read-write instance property:
public string IBaddressType
{
get
{
return _IBaddressType;
}
set
{
_IBaddressType = value;
_IBaddressType = _IBaddressType.PadRight(1);
_IntBlock = _IntBlock.Substring(0, 2861) + _IBaddressType +
_IntBlock.Substring(2862, _IntBlock.Length - 2862);
}
}

private string _IBstreetSDX;
// A read-write instance property:
public string IBstreetSDX
{
get
{
return _IBstreetSDX;
}
set
{
_IBstreetSDX = value;
_IBstreetSDX = _IBstreetSDX.PadRight(4);
_IntBlock = _IntBlock.Substring(0, 2862) + _IBstreetSDX +
_IntBlock.Substring(2866, _IntBlock.Length - 2866);
}
}

private string _IBlocalitySDX;
// A read-write instance property:
public string IBlocalitySDX
{
get
{
return _IBlocalitySDX;
}
set
{
_IBlocalitySDX = value;
_IBlocalitySDX = _IBlocalitySDX.PadRight(4);
_IntBlock = _IntBlock.Substring(0, 2866) + _IBlocalitySDX +
_IntBlock.Substring(2870, _IntBlock.Length - 2870);
}
}

private string _IBlobbySDX;
// A read-write instance property:
public string IBlobbySDX
{
get
{
return _IBlobbySDX;
}
set
{
_IBlobbySDX = value;
_IBlobbySDX = _IBlobbySDX.PadRight(4);
_IntBlock = _IntBlock.Substring(0, 2870) + _IBlobbySDX +
_IntBlock.Substring(2874, _IntBlock.Length - 2874);
}
}

private string _IBprologue;
// A read-write instance property:
public string IBprologue
{
get
{
return _IBprologue;
}
set
{
_IBprologue = value;
_IBprologue = _IBprologue.PadRight(100);
_IntBlock = _IntBlock.Substring(0, 2874) + _IBprologue +
_IntBlock.Substring(2974, _IntBlock.Length - 2974);
}
}

private string _IBinterface;
// A read-write instance property:
public string IBinterface
{
get
{
return _IBinterface;
}
set
{
_IBinterface = value;
_IBinterface = _IBinterface.PadRight(1);
_IntBlock = _IntBlock.Substring(0, 2974) + _IBinterface +
_IntBlock.Substring(2975, _IntBlock.Length - 2975);
}
}

private string _IBstreetMatchFlag;
// A read-write instance property:
public string IBstreetMatchFlag
{
get
{
return _IBstreetMatchFlag;
}
set
{
_IBstreetMatchFlag = value;
_IBstreetMatchFlag = _IBstreetMatchFlag.PadRight(1);
_IntBlock = _IntBlock.Substring(0, 2975) +
_IBstreetMatchFlag + _IntBlock.Substring(2976, _IntBlock.Length - 2976);
}
}

private string _IBlocalityMatchFlag;
// A read-write instance property:
public string IBlocalityMatchFlag
{
get
{
return _IBlocalityMatchFlag;
}
set
{
_IBlocalityMatchFlag = value;
_IBlocalityMatchFlag = _IBlocalityMatchFlag.PadRight(1);
_IntBlock = _IntBlock.Substring(0, 2976) +
_IBlocalityMatchFlag + _IntBlock.Substring(2977, _IntBlock.Length - 2977);
}
}

private string _IBrepeatLocalityFlag;
// A read-write instance property:
public string IBrepeatLocalityFlag
{
get
{
return _IBrepeatLocalityFlag;
}
set
{
_IBrepeatLocalityFlag = value;
_IBrepeatLocalityFlag = _IBrepeatLocalityFlag.PadRight(1);
_IntBlock = _IntBlock.Substring(0, 2977) +
_IBrepeatLocalityFlag + _IntBlock.Substring(2978, _IntBlock.Length - 2978);
}
}

private string _IBignoreInvalidPostcodeFlag;
// A read-write instance property:
public string IBignoreInvalidPostcodeFlag
{
get
{
return _IBignoreInvalidPostcodeFlag;
}
set
{
_IBignoreInvalidPostcodeFlag = value;
_IBignoreInvalidPostcodeFlag =
_IBignoreInvalidPostcodeFlag.PadRight(1);
_IntBlock = _IntBlock.Substring(0, 2978) +
_IBignoreInvalidPostcodeFlag + _IntBlock.Substring(2979, _IntBlock.Length -
2979);
}
}

private string _IBforeignFlag;
// A read-write instance property:
public string IBforeignFlag
{
get
{
return _IBforeignFlag;
}
set
{
_IBforeignFlag = value;
_IBforeignFlag = _IBforeignFlag.PadRight(1);
_IntBlock = _IntBlock.Substring(0, 2979) + _IBforeignFlag +
_IntBlock.Substring(2980, _IntBlock.Length - 2980);
}
}
private string _IBLogonID;
// A read-write instance property:
public string IBLogonID
{
get
{
return _IBLogonID;
}
set
{
_IBLogonID = value;
_IBLogonID = _IBLogonID.PadRight(50);
_IntBlock = _IntBlock.Substring(0, 2980) + _IBLogonID +
_IntBlock.Substring(3030, _IntBlock.Length - 3030);
}
}
public void init()
{
IB = " ";
}



}
}


The whole rigmarole above is necessitated by C# not being able to modify a
string. Once you create a string it is inviolate. You can slice and dice it,
add to it, but to change it you must create a new copy of it. (There are
some very sound reasons as to why it behaves this way, but we won't go into
them here... )

As you can see, this is pretty huge and tiresome, compared to the COBOL
definition of the same block.

But it has some benefits that the COBOL definition doesn't.

The C# Class protects the fields by making sure they cannot be inadvertently
modified, and making them accessible only by GET and SET. (If I wanted to do
any particular validation, I could build it into the SET method of the
individual field; I wouldn't have to re-compile any programs using this
..DLL. In effect, this is now an "interface object". It is encapsulated and
isolated just like it should be. It also includes a method to initialize the
whole block, so programs are relieved of this. They just instantiate the
object and invoke its "init" method...
[
// get an Interface Block object instance...
AVSInterfaceBlockBuilder.AVSInterfaceBlockBuilder objIntBlock = new
AVSInterfaceBlockBuilder.AVSInterfaceBlockBuilder();
// initialize the interface block
objIntBlock.init();
// set the street...
objIntBlock.IBstreet = "Primrose Lane" //(cf. MOVE "Primrose Lane" TO
IBStreet of objIntBlock... not so different, really)
....
etc
]
Because I eventually intend to generate these blocks (it is pretty tedious
coding them by hand :-)) I have taken care to ensure it is 8192 bytes, and
each field entry is reasonably consistent. Smart generation software can pad
it to any size I want, so if the block exceeded 8K it could automatically be
padded to 12K or 16K and a warning issued...

COBOL is excellent for handling fixed length fields and that is why I would
advocate the avoidance of variable length processing in it.

But at a broader level, the encapsulation of parameters into Objects is
simply superior. It is VERY easy to modify or extend parameters when they
are NOT included (directly) in the programs that consume them.

(Whether or not you SHOULD maintain these Classes is a matter for a
different debate. Usually, as in this case, they are not so trivial. Auto
generation seems like the best option, at the moment, to me... Maybe, the
source is kept as COBOL (which is easy to amend, and designed as a "source
oriented" language) and THAT gets updated, then the generator generates a
new .dll for the C# programs that access it. Eventually, I'll just build a
graphic interface to the generator and bypass the COBOL altogether...))

Pete.


.



Relevant Pages

  • Re: Setting id in a dynmaically generated checkboxlist
    ... > protected Repeater Repeater1; ... > public Category(string title, string explanation, ... > public string Explanation ... > private string explanation; ...
    (microsoft.public.dotnet.framework.aspnet)
  • Re: Threading with an object and Session
    ... thread post the mail body directly to the session, ... private string _DatabaseConnection; ... public string EmailNameField ...
    (microsoft.public.dotnet.framework.aspnet)
  • Default.aspx.cs
    ... string strReturn = SendInvitations(txtName.Text, ... private string SendInvitations(string name, string body, string ... emails, string codedString, ArrayList friend) ... public string subject ...
    (microsoft.public.dotnet.languages.csharp)
  • Re: Arraylist.remove problem?? Please help.
    ... static string group; ... private string numb; ... private int messageNumber; ... public string Subject ...
    (microsoft.public.dotnet.languages.csharp)
  • Re: Generics SortedList and DataSource
    ... /// Summary description for Query. ... string m_group; ... public Query(string Name, string Group, bool IsDirect) ... public string Email ...
    (microsoft.public.dotnet.languages.csharp)