Re: [OT] My First C# (warning - long post)
- From: "Pete Dashwood" <dashwood@xxxxxxxxxxxxxxxxxxxxxxxxx>
- Date: Fri, 2 Feb 2007 01:50:17 +1300
"LX-i" <lxi0007@xxxxxxxxxxxx> wrote in message
news:d8eb1$45c17062$454920f8$31633@xxxxxxxxxxxxxx
Pete Dashwood wrote:
Hi Daniel,
Unfortunately, much as I'd like to, I'm just too busy at the moment to
analyse this properly.
Fortunately, Andrew is doing so (I had a quick look at his comments and
endorse them 100%) and one set of criticisms is probably all you need on
a first attempt :-)
I'm a big guy (well, metaphorically). I can take it.
I formed some first impressions from a quick look (before I saw Andrew's
comments.... :-)) and they were as follows:
1. It is a procedural translation into an OO environment. Even down to
the "Working-storage" at the top of the Class... :-)
Aw man, cut me some slack - show me a COBOL program with less than 15
working-storage variables! :)
I did cut you some slack... Have a look at properties if you really want
global variables
(The reason I did this that way,
especially for the block of private ones, was just so that the memoryNo, and I wouldn't do it... :-)
didn't have to be loaded every time. Can you imagine loading that array
of COBOL keywords every time isCobolKeyword is called?)
2. You show an excellent grasp of using functions and, at the
nitty-gritty level you have it sussed. (I think you may be over-using
Trim()...
"Convert.ToChar(dr["element_type"].ToString().Trim().Substring(0,1))"
seems a bit unnecessary to me, when all you are wanting is one byte, but
I haven't checked the details...:-)
You'd think that you could cast a substring of one character TO a
character, wouldn't you? Yes, the Trim() is probably extra now, but that
was my attempt to get it to quit griping at me that I had given it a
"String", when it wanted a "char". (I know in Java you can't do a switch
on a string - I'm guessing that it's that way in C# as well. If not, then
I spent 20 minutes wasting my time... :> Which wouldn't surprise me to
find out...)
Don't make Java assumptions about C#. You can certainly switch on a char or
string, (as long as they are constant). When it "gripes" at you, there is a
reason. I consider these gripes as a voice saying: "Pete, you are about to
learn something..." :-) Fortunately, as the learning process proceeds, the
voice becomes less insistent. But you have to listen to it, do the homework,
and not just look for a way to dismiss it as an irritation... :-)
Here's a sample from live code that covers Casting string to Char, setting
up a Global property, and managing a COBOL data block in C#...
}
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 -
_IBreturn.Length);
}
}
(As you can see, I do not share your aversion to braces surrounding code
blocks being on a new line, and I actually find this helpful...)
The "set" method inserts a Pic x(5) return code into the start of an
interface block, defined as a COBOL structure of 8192 bytes (this is for
compatibility with COM BSTRING type.)
The return code must be padded with zeroes if it does not occupy the full 5
bytes. Although _IBreturn is a string, it must be padded with Chars. You may
consider this is "cheating" so here's a direct cast to char, also taken from
live code :-)...
string temp = ", [";
char[] trimChars = temp.ToCharArray();
(There is no need for ConvertTo, SubString or Trim as any string contains
the knowledge to cast itself to a char array...)
The final action of the "set" method above is to update the COBOL interface
block with the new return code. Note that the return code is a private field
that cannot be accessed other than by means of the get and set methods; the
public copy of the field automatically uses these methods when it is
referenced. You could argue that this is unnecessary; why not just slice a
subtring of _intBlock when you want the return code? It is unwieldy to
keep referencing substrings of an 8K string simply to get 5 bytes. Keeping
each field in the block separate as a private property and updating the
block when they get changed, by means of their set methods, seems to work
pretty well. I can aso "audit" the integrity of the block because I have
each field of it as a separate entity. The entire block can be easily
reconstructed from these fields and that might not be so easy if it is being
sliced left right and centre. Finally, this approach lends itself to
automation and can be easily generated from COBOL definitions.
But, most importantly of all, the code that deals with the fields in the
block can simply reference them, and the block is automatically updated if
any of the fields are changed (remember what I said about support methods
doing the lower-order tasks?) so there is no concern about "housekeeping"
when working on these fields and, because they are public properties, they
are visible to all methods of the Class.
It's kind of like "intelligent working-storage"... :-)
3. The embedded SQL is just a hangover from procedural code; it is
inefficient and ugly. Think in tiers; separate data access from business
logic. Treat db connections as precious; don't hold them any longer than
you need to. I posted a link previously which outlines the C# approach
and it is quite different from the procedural embedded SQL approach.
(Since my own stuff is now working, I can also confirm that it is VERY
fast...)
See my post to Andrew on this topic - how?
Did you even look at the article I referenced? :-) It not only explains How,
it shows WHY :-)
Setting a connection and issuing SQL is pretty unavoidable, but after that
there is a big difference between using a SQL reader and using a
DataAdapter/DataSet. The DataSet has methods and properties that are really
useful (and cool :-)). You simply don't get them if you just write embedded
SQL or open a cursor. The DataAdapter allows you to process everythng and
only apply the updates at the end when you are satisfied - the DataSet
automatically notifies errors if you change something incorrectly.
Have a look at the Data facilities in VS 2005. If you know what you're going
to be accessing, it will build the code for you in minutes. My stuff is
completely dynamic and designed to work with any database of a given family,
so I need to know what the structure is at runtime. DataSet methods and
properties give me that. It was really problematic for me NOT to be able to
use the facilities in VS 2005 because of the unknown nature of what I would
be accessing. Time and again I realised that the IDE would generate the code
if I could simply tell it what I wanted. I spent many hours combing the
support and help to understand the new (to me) concepts and finally get what
I needed. I still can't believe it actually works, but it does :-)
4. I think you are very lucky to have someone like Andrew looking at it.
I read his comments and agree almost entirely. (I think 10 lines is a
bit too rigid a rule, but the principle is correct.). In OO, as in most
online processing, "small is beautiful"... Andrew's point about
refactoring is an excellent one and I wouldn't have thought of that as a
good way to improve what you have; I've learned from this interchange :-)
I really appreciate him doing it.
I realized today how much of a geek I am. I have Visual C# 2005 Express
Edition, Eclipse (for Java 2 1.5), Fujitsu COBOL, and Visual SlickEdit all
on one machine. Wow...
A REAL geek would be able to write Fortran in ALL of them... :-)
5. You deserve credit for posting ANY code here, and to post a first
attempt, is brave and admirable. I know you won't take the comments to
heart in a negative way.
I won't. Of course, that's also why I posted my list of caveats before
the code - there are things about it I don't like, but when the IDE or
shop standards enforce "style", it's hard to take any complaints about it
personally.
6. You might think about offloading a lot of the literals into external
data. C# provides a number of places where you can put stuff... System
collections, XML files, configuration data, to name a few. The COBOL
Reserved Word list could be an XML file that gets loaded once at startup,
rather than being embedded in the program.
I was thinking that there *had* to be a better way to do that. Can you
make a static XML that gets "built into" (whatever the C# term for that
would be) the .dll file?
For my money, you need to start thinking in terms of a production line.
Think about a series of (small) machines (components) that take scrap
metal in one end and push knives and forks out the other. Each machine
carries out another step in the process, each machine does exactly what
it does, and functionality does not overlap. (Think encapsulation and
"black boxes"). Some machines provide support functions to machines on
the main line, but for each machine, the goals it must achieve are clear,
and the primary focus for it, from which it must not be distracted by
having to do ancilliary and support functions (like accessing databases).
Think of machines in each layer (tier) of the production process. (A
component needs to validate, retrieve, or update certain data? It should
focus on what it is going to DO with that data and leave the "lower
order" functions to other components who deal with that. It can simply
activate a "retriever" and know that what comes back is valid and timely
or whatever...) Activate the retriever; take what it returns, get on with
what this component is really about...:-)
I'd really love to do this... Gotta get the grey matter aligned
properly...
Some of the above was intended to help in this area and to put my money
where my mouth is...:-) I really am so busy at the moment (I'm
force-feeding new information and concepts into myself , as well as
developing, so I'm pretty tired by the end of the day), but I'd like to try
and contribute if I can.
Still, you have demonstrated a really good grasp of the language itself,
the program works, and it can be made more elegant fairly easily. All in
all, pretty good for a first attempt :-)
Thanks. It really is a piece of cake - I've converted three ASPs to
ASP.NET/C# pages in 2 days (6 if you count the little ones I'm working on
now). It took me a little over a day on the first one, then it just
clicked. Of course, it's probably still procedural C#, but it's fast. :)
At this point, it really doesn't matter whether it is technically elegant or
REAL OO... it works. As you write more of it and consider more approaches,
you'll pick up the OO stuff.
This DB abstraction layer would be good for our system as a whole. The
entire thing will be ASP.NET/C# when we're (er, I guess that should be
"they're") done. I'm guessing that, once I get that built, we would just
give it a namespace (maybe CSCS.DataUtilities or something like that),
then import, er, "using" it in our classes/pages?
Something like that, certainly...
Pete.
.
- Follow-Ups:
- Re: [OT] My First C# (warning - long post)
- From: LX-i
- Re: [OT] My First C# (warning - long post)
- References:
- Re: [OT] My First C# (warning - long post)
- From: LX-i
- Re: [OT] My First C# (warning - long post)
- Prev by Date: Re: My First C# (warning - long post)
- Next by Date: Re: My First C# (warning - long post)
- Previous by thread: Re: [OT] My First C# (warning - long post)
- Next by thread: Re: [OT] My First C# (warning - long post)
- Index(es):
Relevant Pages
|