Home > Archive > Cobol > February 2007 > Re: My First C# (warning - long post)
You are viewing an archived Text-only version of the thread.
To view this thread in it's original format and/or if you want to reply to
this thread please [click here]
| Author |
Re: My First C# (warning - long post)
|
|
| andrewmcdonagh 2007-02-05, 6:55 pm |
| On Feb 5, 1:42 am, LX-i <lxi0...@netscape.net> wrote:
> andrewmcdonagh wrote:
>
snipped
>
> I like! I had been doing some working with namespaces and the like - I
> took what you did, and some research prompted by Pete's comment about
> the Dictionary class, and twisted it a bit. There is a List<T> class as
> well, which doesn't require key/value combinations, and has a "Contains"
> method. This is what it looks like now...
>
> -8<--
>
> using System;
> using System.Collections.Generic;
> using System.Text;
>
> namespace CSCS.Util
> {
> class CobolKeywordDictionary : KeywordDictionary
> {
> // This is loaded with the keywords from the below table
> private List<String> cobolKeywords = new List<String>();
>
> // A list of COBOL keywords
> private String[] keywords =
> { [oh yeah]
> };
>
> public CobolKeywordDictionary()
> {
> for (int i = 0; i < keywords.Length; i++)
> {
> cobolKeywords.Add(keywords[i]);
> }
>
> }
> public bool isKeyword(String keyword)
> {
> return cobolKeywords.Contains(keyword.ToUpper());
> }
> }
>
> }
>
> ->8--
Thats ok, but the performance is going to suffer.
Every time you create an instance of this class, its going to:
1) Create a Array of the string literals
2) Copy that array one by one into a List
Then everytime you call 'isKeyword()' on your class, it asks the List
if it contains the keyword. Which basically is going to loop through
its internal data structure, one at a time until it find the keyword
or finishes not finding it..
Where as......
using System;
using System.Collections.Generic;
using System.Text;
namespace CodeStats
{
class FastCobolKeywordDictionary : KeywordDictionary
{
static Dictionary<String, String> keywords = new
Dictionary<string,string>();
// Static Constructor - means it will be called
// once and only once, sometime between when the
// program begins and the class is instantiated.
static FastCobolKeywordDictionary()
{
//...
keywords.Add("AUTHOR", null);
keywords.Add("BEFORE", null);
keywords.Add("BINARY-1", null);
// ....
}
public bool isKeyword(String keyword)
{
return keywords.ContainsKey(keyword);
}
}
}
This class has a 'static constructor', which is called once and only
once by the runtime system for you, at some point between the program
starting and the first usage of the class.
Plus, when 'isKeyword()' is called, it asks the Dictionary if it
contains the keyword, which does a super fast lookup, which out
looping through the entire collection.
Dictionarys (And Hashtables) internally separate their contents into
buckets based upon the hashcode of the Key. So when asked
'ContainsKey(...) they only need to look in the relevant (small)
bucket for a match, instead of the entire collection.
>
> I could still have the keywords in a separate XML file - but with the
> reluctance of our customers to embrace new technology, that keyword list
> won't be changing anytime soon.
Sure and personally I wouldn't bother, it doesn't strike me like
something that would change very often.
>
> This is really stuff! The intent of this look-up is to keep us
> from hitting the database to determine if the name is a database name.
> However, it just hit me when I was typing this e-mail - I could make
> DataSets from the database tables, convert them to lists, and use the
> list lookups for the cull building! No repetitive database access!
>
> (You were just the witness to a huge light coming on in my head... And
> no, it's not just the glare from where I don't have hair there
> anymore... ;) )
>
oh ok...be care, this caching technique is widely know and so are its
problems.
e.g. when are updates applied to cache,
concurrency issues
etc...
> I had tried to implement the above with a predicate, but it seemed like
> cheating. Since I can't pass a parameter to the predicate method, I had
> created a private String that I set to the keyword, then used the
> StartsWith method on that string. My problem with that, though, is that
> "ACC" came back as true, since "ACCEPT" starts with "ACC". I was going
> to put a second check in there, using EndsWith, and then I said to
> myself, this needs a "Contains" method or something. :) Looks like I
> wasn't alone.
>
Yes best to just use '==' as this checks the string values rather than
their references.
> And - your inteface - I could come up with something like
>
> NetworkRecordKeywordDictionary : KeywordDictionary
> NetworkItemKeywordDictionary : KeywordDictionary
> RelationalTableKeywordDictionary : KeywordDictionary
> RelationalItemKeywordDictionary : KeywordDictionary
>
> I actually *will* use a dictionary on the relational items, as I'll have
> a proc data name (ex. R119-Home-ELC) that references an actual database
> name (HOME_ELC in the HOME_USER table). I may have to add another
> method to the interface for those, or change the return type - of
> course, I guess at that point it's not really using the
> KeywordDictionary interface. :)
note sure I follow you here...
The interface is there to generalise the method, so if you change it
to specialise again, then you code will need to
if (cobol)
return cobolKeywordDictionary.isKeyword(something);
else
return someOtherKeywordDictionary.isKeyword(Someting,
andSomethingElse);
always try to 'push' the knowledge of which one to call, to the other
class (Our keyword dictionaries in this case), that way we can simply
someDictionary.isKeyword(something);
>
> Man - I'm excited. :) I really wish that there was a generic way to
> code, though, that didn't have to know about what sort of database
> backend you have. SqlDataAdapter is the DataAdapter for SQL Server,
> while OdbcDataAdapter is the one for ODBC. If I could "genericise" (is
> that a word?) those in the code, and just have it use whatever type of
> connection I passed to it, I could actually run this against a copy of
> the SQL Server database on my laptop (in MySQL or Access or something
> else). (And yes, I know I could just code it with ODBC, but I don't
> want it to run generically in production when there are libraries
> specifically enhanced for it.)
>
And that is a great technique - One I'd endorse.... which a twist...as
above. push the knowledge of the Connection to the data source class
itself, or pass it when you create an instance of the class.
I tend to always abstract the data reading/writing behind a general
purpose 'plain old c# ' interface, and let the implementors of that
interface decide how/where to get their data from.
e.g.
interface LineCountReporter
{
void WriteTotalLineCount(String sourceFilename, int32
lineCount);
}
class MySqlLineCountReporter : LineCountReporter
{
public MySqlLineCountReporter
{
dbConnection = // set the dbConnection here...
}
// provide the connection at object creation time only.
public MySqlLineCountReporter(Connection connection)
{
dbConnection = connection
}
public void WriteTotalLineCount(String sourceFilename, int32
lineCount)
{
// use MySql database code to write to a table.
}
}
>
>
>
>
>
>
> That's great. :) I appreciate the list of steps you took in
> refactoring the code, too - I haven't commented about the process much
> because I so excited about the results, but I wanted you to know that I
> did read it, and understand why you did what you did.
>
> Thanks again for a great post, and lots of help! :) Before you know
> it, I'll be able to put C# on my resume! (Not that they look at resumes
> in the military...)
>
| |
| Howard Brazee 2007-02-09, 6:55 pm |
| On Fri, 9 Feb 2007 11:56:29 +1300, "Pete Dashwood"
<dashwood@removethis.enternet.co.nz> wrote:
>For some time now I have been trying to explain that an OO approach removes
>the need for source code maintenance in the traditional sense. Classes and
>methods should be encapsulated and "do what they do". When change is
>required it should be new interfaces or extensions and NOT an internal
>change to already working code. Apart from the obvious benefit of NOT
>requiring regression testing, this approach also simplifies maintaining
>applications. I came to learn this by working with COM component development
>over a number of years.
We've been modifying our granularity of our programs forever. We
replaced machine language with assembler with compiled. When our
compiler company changes the code behind the COMPUTE command, we
assume it has been fully tested and do not do regression testing for
all of the programs that have COMPUTE in them.
Well, the granularity is bigger. If OO is working right, instead of
the COMPUTE command, we now have a Compute object. The supplied
libraries are bigger and we're more a bit more likely to be bitten
when they change than when the COMPUTE command changes - but we're
still pretty safe.
But we're more likely to be bitten when a CoBOL copy member gets
changed, or a CoBOL called program gets changed. And we're more
likely to get bitten when a local shop object gets changed. So lots
of shops avoid using much re-use of our objects. Complex
environments such as that which Microsoft has to create Windows end up
with bugs within objects. But we really don't have a choice. We
are in those complex environments and have to ride the wave.
|
|
|
|
|