Search

Categories

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Send mail to the author(s) E-mail

# Tuesday, 25 August 2015

What is a class?

Holds state (properties or fields)
Has behaviour (methods)

What is a closure?

“A closure is a block of code which can be executed at a later time, but which maintains the environment in which it was first created ie it can still use the local variables of the method which created it, even after that method has finished executing”
http://stackoverflow.com/questions/428617/what-are-closures-in-net

Closing over something that may go out of scope

// Action is a delegate which doesn't return a value Action action = CreateAction(); //Here we can see that the action returned by CreateAction still has access to the counter variable, //and can indeed increment it, even though CreateAction itself has finished. action(); action(); } static Action CreateAction() { int counter = 0; Action a = delegate { counter++; Console.WriteLine("counter={0}", counter); }; return a; }

 

A Function:

// setting up state of function Func<int, int> fn2 = GetMultiplier(2); //var fn3 = GetMultiplier(3); Console.WriteLine(fn2(2)); //outputs 4 Console.WriteLine(fn2(3)); //outputs 6 //Console.WriteLine(fn3(2)); //outputs 6 //Console.WriteLine(fn3(3)); //outputs 9 } static Func<int, int> GetMultiplier(int a) { int multiplier = a; Func<int, int> multiplierFunction = delegate(int b) { return multiplier * b; }; return multiplierFunction; }


and again:

Action a = GiveMeAction(); a(); // i = 1 a(); // i = 2 a(); } static Action GiveMeAction() { int i = 0; Action a = delegate { i++; }; // Returning a method/function which captures the i scope (closure) return a; }
https://www.youtube.com/watch?v=gBO_4BMbsO8

asdf

// A delegate that accepts a string and returns a string Func<string, string> myFunc = delegate (string var1) { return "some value"; }; string myVar = myFunc("something"); Console.Out.WriteLine($"myVar is {myVar}");

When to use closures?

LINQ is built using clousures

  • Simplify interfaces
  • Delayed execution
| | # 
# Friday, 17 October 2014
  • Encapsulation
  • Inhertence
  • Polymorphism

Encapsulation

Glance test… what abstractions are there… ie for a code review, shouldn’t be primitive types around.

class Program { static void Main(string[] args) { var date = new List<DateTime>(); var open = new List<decimal>(); var high = new List<decimal>(); var low = new List<decimal>(); var close = new List<decimal>(); var lines = File.ReadAllLines(args[0]); for (int i = 1; i < lines.Length; i++) { var data = lines[i].Split(','); date.Add(DateTime.ParseExact(data[0], "M/d/yyyy", CultureInfo.InvariantCulture)); open.Add(decimal.Parse(data[1])); high.Add(decimal.Parse(data[2])); low.Add(decimal.Parse(data[3])); close.Add(decimal.Parse(data[4])); } for (int i = 0; i < date.Count - 4; i++) { if (open[i] > high[i + 1] && close[i] < low[i + 1]) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("Pivot downside {0}", date[i].ToShortDateString()); } if (open[i] < low[i + 1] && close[i] > high[i + 1]) { Console.ForegroundColor = ConsoleColor.Green; Console.WriteLine("Pivot upside {0}", date[i].ToShortDateString()); } } } }

Business logic doesn’t present itself as no abstractions (only primitive abstrations)

The Big Encapsulation

Break up procedures into Methods

Higher density of information

class Program { static void Main(string[] args) { const string filename = "msft.csv"; var ana = new StockQuoteAnalyzer(filename); ana.LoadQuotes(); ana.AnalyzeQuotes(); } } class StockQuoteAnalyzer { private readonly string _filename; readonly List<DateTime> _date = new List<DateTime>(); readonly List<decimal> _open = new List<decimal>(); readonly List<decimal> _high = new List<decimal>(); readonly List<decimal> _low = new List<decimal>(); readonly List<decimal> _close = new List<decimal>(); public StockQuoteAnalyzer(string filename) { _filename = filename; } public void LoadQuotes() { var lines = File.ReadAllLines(_filename); for (int i = 1; i < lines.Length; i++) { var data = lines[i].Split(','); _date.Add(DateTime.ParseExact(data[0], "M/d/yyyy", CultureInfo.InvariantCulture)); _open.Add(decimal.Parse(data[1])); _high.Add(decimal.Parse(data[2])); _low.Add(decimal.Parse(data[3])); _close.Add(decimal.Parse(data[4])); } } public void AnalyzeQuotes() { for (int i = 0; i < _date.Count - 4; i++) { if (_open[i] > _high[i + 1] && _close[i] < _low[i + 1]) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("Pivot downside {0}", _date[i].ToShortDateString()); } if (_open[i] < _low[i + 1] && _close[i] > _high[i + 1]) { Console.ForegroundColor = ConsoleColor.Green; Console.WriteLine("Pivot upside {0}", _date[i].ToShortDateString()); } } } }

Defining classes to separate rules and responsibilities.. http://www.wirfs-brock.com/DesignBooks.html

Object responsibilities and roles – keep separated:

  • Knowing
  • Deciding
  • Doing

Little Abstractions

6 classes now instead of 2

Is this too much – a big problem in design!  If its a throwaway program, then yes.

  • KISS
  • YAGNI

Design should be iterative, and driven by immediate needs.  Some consideration for what's going to change in the future.  Concrete use/test cases are good.

Replacing dot net primitives, with own abstractions..

Separate

  • Knowing (domain) eg StockQuote encapsulates knowledge (including compares)
  • Deciding (business logic) eg Analyzer, ReversalLocator
  • Doing (input, output to screen etc..)

StockQuoteAnalyzer isn’t tied to the ConsoleApp anymore. Can be used in webapp, service etc..

image

11/14/2004 look for.

image
Opened above the previous high, and below the previous low.

Inheritance

Template method pattern (abstract base class)

But it tightly binds things together.  Bad. Harder to make changes.

Interfaces

A class can implement multiple interfaces.

Directional Dependencies

Passing in a dependency

Modern OOP

  • Encapsulation is king
  • Interfaces and composable
  • Small abstractions are powerful
| | # 
# Wednesday, 23 December 2009

Symbolic constants vs Enumerated Types'

These constants are handy when cheking on the setter (as can use an int range)

    public const int APARTMENT = 1;
    public const int COMMERCIAL = 2;
    public const int HOME = 3;
 
    public int BuildingType
    {
        get { return buildingType; }
        set
        {
            if (value >= APARTMENT && value <= HOME)
                buildingType = value;
        }
    }
This keyword
public clsBuilding()
    {
        address = "Not closed yet";
    }
 
    public clsBuilding(string addr, decimal price, decimal payment, decimal tax, decimal insur, DateTime date, int type)
        : this() // good practise to call initial constructor first..second constructor will overwrite address = "Not closed yet"
    {
        if (addr.Equals("") == false)
            address = addr;
        purchasePrice = price;
        monthlyPayment = payment;
        taxes = tax;
        insurance = insur;
        datePurchased = date;
        buildingType = type;
    }
Base keyword
    public clsCommercial(string addr, decimal price, decimal payment,
                        decimal tax, decimal insur, DateTime date, int type) :
                        base(addr, price, payment, tax, insur, date, type)
    {
        buildingType = type;   // Commercial type from base
    }

this is calling the bases’ constructor.

can also call base methods from the derived (child) class.

Polymorphism

essentially this means we can send the same message to a group of different classes and each class will know how to respond correctly. eg

image

        lstMessages.Items.Add(myApt.RemoveSnow());
        lstMessages.Items.Add(myComm.RemoveSnow());
        lstMessages.Items.Add(myHome.RemoveSnow());

clsApt and clsComm have overridden methods and respond with different phone numbers.  clsHome doesn’t have a RemoveSnow method and responds as above.

Abstract Classes

To prevent instantiation of the base class ie if it makes no sense.

public abstract class clsDeciduous
{
 
Virtual and Override
The method may be overridden in a derived class.
 
    public virtual string RemoveSnow()
    {
        return whichType[buildingType] + ": No snow removal service available.";
    }

And in the derived class:

public override string RemoveSnow()
    {
        return "Commercial: Call Acme Snow Plowing: 803.234.5566";
    }

To prevent further inheritence use public sealed class.

| | # 

From msdn.

        // i is compiled as an int
        var i = 5;
 
        // s is compiled as a string
        var s = "Hello";
 
        // a is compiled as int[]
        var a = new[] { 0, 1, 2 };
 
        // person is compiled as an anonymous type
        var person = new { Name = "Terry", Age = 34 }; 
Anonymous types:
 
var v = new { Amount = 108, Message = "Hello" };

Anonymous types provide a convenient way to encapsulate a set of read-only properties into a single object without having to first explicitly define a type

| | # 

See: http://www.programgood.net/2009/10/20/TestDrivenDevelopmentInNETDALCh5.aspx

ADO.NET (ActiveX Data Objects) consists of two primary parts:

Data provider

These classes provide access to a data source, such as a Microsoft SQL Server.  Each data source has its own set of provider objects, but they each have a common set of utility classes:

  • Connection: Provides a connection used to communicate with the data source.
  • Command: Used to perform some action on the data source, such as reading, updating, or deleting relational data.
  • Parameter: Describes a single parameter to a command. A common example is a parameter to a stored procedure.
  • DataAdapter: A bridge used to transfer data between a Data source and a DataSet object (see below).
  • DataReader: Used to efficiently process a large list of results one record at a time. It allows records to be accessed in a read-only, forward-only mode, i.e., records have to be accessed in sequential order; they can neither be randomly accessed nor can a record which has been processed previously be accessed again.
DataSets

DataSet objects, a group of classes describing a simple in-memory relational database,

  • A DataSet object represents a schema (either an entire database or a subset of one). It can contain tables and relationships between those tables.
    • A DataTable object represents a single table in the database. It has a name, rows, and columns.
      • A DataView object overlays a DataTable and sorts the data (much like an SQL "order by" clause) and filters the records (much like an SQL "where" clause) if a filter is set. An in-memory index is used to facilitate these operations. All DataTables have a default filter, while any number of additional DataViews can be defined, reducing interaction with the underlying database and thus improving performance.
        • A DataColumn represents a column of the table, including its name and type.
        • A DataRow object represents a single row in the table; it allows reading and updating of values in that row, likewise retrieving any rows that are related to it through a primary-key foreign-key relationship.

OLE-DB is a replacement for ODBC.

image

When adding in a reference (a COM – Component Object Model).. I had to restart VS to get Resharper/VS to recognize and give me intellisense.

The reference was an ADOX reference – ADO ext 2.8 for DDL and Security.  We have to use this as the OLE DB features do not give create new database functionality.

int index;
        string newDB;
        string dbName = txtDatabaseName.Text;
        try
        {
            if (dbName.Length == 0)
                return;
            index = dbName.LastIndexOf('.');
            if (index == -1) // no secondary filename
            {
                dbName += ".mdb";
            }
            string pathName = Application.StartupPath.ToString();
            string combinedName = Path.Combine(pathName, dbName);
            ADOX.CatalogClass myCat = new ADOX.CatalogClass();
            newDB = CONNECTSTRING + combinedName + ";" + CONNECTSTRINGPART2;
            myCat.Create(newDB);
            myCat = null;
        }
CreateDatabase_website

image

Good bit of functionality, if you double click on an element in the list, it deletes it.

void lstFieldsToAdd_DoubleClick(object sender, EventArgs e)
    {
        ListView.SelectedIndexCollection indexes = lstFieldsToAdd.SelectedIndices;
 
        foreach (int index in indexes)
        {
            lstFieldsToAdd.Items[index].Remove();
        }
    }

Writing to the database he uses a class in clsDB called ProcessCommand

However to read data he does this from a form object.  So only using the clsDB to get the connection string.

OleDbConnection myDB = new OleDbConnection();
OleDbDataReader myReader;
OleDbCommand myCommand;
clsDB myData = new clsDB("Friend");
 
try
{
    myDB.ConnectionString = myData.getConnectString + dbName;
    myDB.Open();
    if (txtLastName.Text.Length != 0)
        sql = "SELECT * FROM Friend WHERE LastName = '" +
              txtLastName.Text + "'";
    else
        sql = "SELECT * FROM Friend WHERE ID = " + txtRecordID.Text;
  
    ClearFields();
 
    myCommand = new OleDbCommand(sql, myDB);
    myReader = myCommand.ExecuteReader();
    if (myReader.Read() == true)
    {
        record = (int)myReader[0];
        txtRecordID.Text = record.ToString();

image

Querying and DataGrid

image

Changing properties on the grid, such as docking to allow window resizing, colour schemes, formatting of cells.

Double click on the database table automatically runs the execute query.  User can drag column headers around, and sort each column.  User can add/edit/del data (code not implemented in this example).

image

LINQ

image

var query = from p in numbers // the linq query
                    where p > lo && p < hi
                    select p;
        foreach (var val in query) // display results
        {
            lstOutput.Items.Add(val.ToString());
        }

image

This is an interesting construct, using anonymous types.  What this is actually saying

var friends = new[]
                      {
                          new {name = "Tom", state = "IN"},
                          new {name = "Alice", state = "VA"},
                          new {name = "Tammy", state = "IN"},
                          new {name = "Ann", state = "KY"},
                      };

 

var query = from p in friends
                        where p.state == txtLow.Text
                        select p;
 
            foreach (var val in query)
            {
                lstOutput.Items.Add(val.name.ToString() + ", " + val.state.ToString());
            }
| | # 
# Tuesday, 22 December 2009

 

Uses recursion.  And System.IO

image

Had a debugging issue in the code, where there was an extra space which caused a –1 to be displayed in Directories found.

The catch block in the class was suppressing the error, so I put in a throw statement in the catch block which stopped the VS debugger, and pointed me to the correct place.

catch (Exception ex)
{
   //throw;  // great while debugging to get the line number of the exception
   return -1;
}
Error Logger

A useful class that writes to a textfile log, then can read back from it.  Creates the file if it doesn’t exist.  Appends to the file if it does exist.

image

Reading:
string pfn = Path.Combine(pathName, fileName);
            if (File.Exists(pfn))
            {
                sr = new StreamReader(pfn);
                buff = sr.ReadToEnd();
                sr.Close();
                return buff;
            }

Writing:
sw = new StreamWriter(Path.Combine(pathName, fileName), true);
                sw.WriteLine(currentDT.ToShortDateString() + ", " +
                             currentDT.ToShortTimeString() + ": " +
                             errorMessage);
                sw.WriteLine("-----------------------------");
                sw.Close();
Random Access Files

image

Uses frmMain for display logic, and clsRandomAccess for writing and reading data to disk.

In clsRandomAccess there are Property Methods for all fields:

public string FirstName
    {
        get
        {
            return firstName;
        }
        set
        {
            if (value.Length > 0)                   // Do we have a string?
            {
                firstName = value;
                if (firstName.Length > NAMESIZES)   // Too long
                {
                    firstName = firstName.Substring(0, NAMESIZES);  // Trim it.
                }
            }
        }
    }

All methods return a 0 if error, otherwise 1 if success.  Uses a binarywriter, and has to calculate the size of each record to know where to read to.

 

Serialize and Deserialize

image

Uses [Serialize] attribute on clsSerial class.

/// <summary>
 /// To serialize the contents of the class
 /// </summary>
 /// <param name="serial"></param>
 /// <returns>0 on error, 1 otherwise</returns>
 public int SerializeFriend(clsSerial myFriend)
 {
     try
     {
         BinaryFormatter format = new BinaryFormatter();
         FileStream myStream = new FileStream("Test.bin", FileMode.Create);
         format.Serialize(myStream, myFriend);
         myStream.Close();
     }
     catch (Exception ex)
     {
         string buff = ex.Message;
         return 0;
     }
     return 1;
 }
Multiple Document Interface

image

| | # 
# Monday, 21 December 2009

Before tackling generics, I had to understand the Quicksort algorithm.  Uses recursion.

From http://www.mycstutorials.com/articles/sorting/quicksort

image

Here is the

And back to the beginners book :-)  Here I am using the preprocessor directives in the frmMain class to make sure I get the same random numbers each time I run the app.

#define DEBUG
//#undef DEBUG

image

Onto Generics:

image

image

image

Pretty cool the same algorithm can sort these different kinds of data.  The reason they can is that each of these types implements a method called CompareTo.

public class clsQuicksort<thing> where thing : IComparable   //thing has to implement IComparable ie implements CompareTo.

And we can check that the type passed in implements CompareTo, by checking that it implements the IComparable interface.

using generics here so I can do this:

clsQuicksort<int> iSort = new clsQuicksort<int>(iData);
clsQuicksort<long> lSort = new clsQuicksort<long>(lData);
clsQuicksort<double> dSort = new clsQuicksort<double>(dData);
clsQuicksort<string> sSort = new clsQuicksort<string>(sData);

otherwise I would have had to make a different sort class for each type (just like that top of this blog article)

clsSortIntegers mySort = new clsSortIntegers(data); // passing the integer data array to be sorted through the constructor
mySort.quickSort(0, data.Length - 1); // sort the data
Refactorings:
/// <summary>
    /// Rather than doing a case statement to switch between displaying the iData, lData, dData, sData
    /// which is all in context, it is less code to write a generic method to handle this.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="stuff"></param>
    void ShowGenericData<T>(T[] stuff) // so can pass any type in here that implements ToString
    {
        for (int i = 0; i < stuff.Length; i++)
        {
            if (whichListBox == SORTED)
                lstSorted.Items.Add(stuff[i].ToString());
            else
                lstUnsorted.Items.Add(stuff[i].ToString());
        }
    }
 
and another:
/// <summary>
    /// Performs the data swap for quickSort()
    /// </summary>
    /// <param name="pos1">index to first value to swap</param>
    /// <param name="pos2">index to second value to swap</param>
    //void swap(int pos1, int pos2)
    //{
    //    thing temp;
    //    temp = data[pos1];
    //    data[pos1] = data[pos2];
    //    data[pos2] = temp;
    //}
 
    /// <summary>
    /// rewritten swap method that does not rely on class scope.  
    /// can take any type of data
    /// </summary>
    /// <param name="pos1"></param>
    /// <param name="pos2"></param>
    void swap<T>(T[] stuff, int pos1, int pos2)
    {
        T temp = stuff[pos1];
        stuff[pos1] = stuff[pos2];
        stuff[pos2] = temp;
    }

This is very nice as we have

  • strong type checking
  • no boxing/unboxing
  • no casting hasstles
| | # 
# Friday, 18 December 2009

image

rb – Radio Button

cbk - Checkbox

cmb – Combobox

dtp – DateTimePicker

Debug helper code

int exp1 = 5;
int exp2 = 0;
try
{
    throw new ArgumentOutOfRangeException();
    int result = exp1 / exp2;
}
catch (DivideByZeroException)
{
    MessageBox.Show("Expression 1 is 0, please reenter");
}
catch (Exception ex)
{
    MessageBox.Show("Bad things are afoot:\r\n" + ex.Message + "\r\n" + ex.StackTrace);
}
finally {
    MessageBox.Show("and finally");
}
| | # 
# Monday, 14 December 2009

Was trying to figure out why something worked: http://stackoverflow.com/questions/1896871/c-calling-a-method-and-variable-scope

From http://rapidapplicationdevelopment.blogspot.com/2007/01/parameter-passing-in-c.html and Jon Skeets: http://www.yoda.arachsys.com/csharp/parameters.html

 

static void Main(string[] args)
    {
 
        int i = 5; // #1 a value type.. i and j are both 5, but seperate
        int j = i; 
        j = 10;
        Console.WriteLine(i); // prints 5
 
        StringBuilder sb1 = new StringBuilder("2.hello"); // #2 a reference type
        StringBuilder sb2 = sb1;  
        sb2.Append(" world");
        Console.WriteLine(sb1); // prints 2.hello world
 
        string s1 = "3.hello"; // #3 Immutable reference type
        string s2 = s1;  // s1 and s2 actually point to the same memory location now
        s2 += " world"; // seems like they split now.. behave like value types
        Console.WriteLine(s1); // prints 3.hello
 
        int a = 5; // #4 Value type passed by value
        Change(a); // equivalent to instantiating a new variable and assigning it the the first.
        Console.WriteLine(a);  // prints 5.
 
 
        StringBuilder ssb1 = new StringBuilder("5.hello"); // #5 reference types passed by value
        CChange(ssb1); 
        Console.WriteLine(ssb1); // prints hello world
 
        int g = 5; // #6 value type passed by reference
        DChange(ref g); 
        Console.WriteLine(g); // prints 10
 
        StringBuilder sssb1 = new StringBuilder("7.hello"); // #7 reference type passed by reference
        EChange(ref sssb1);
        Console.WriteLine(sssb1.ToString()); // null ref exception
 
        Console.ReadLine();
    }
 
    static void EChange(ref StringBuilder sssb2)
    {
        sssb2.Append(" world");
        sssb2 = null;
    }
 
    static void DChange(ref int g)
    {
        g = 10;
    }
 
    static void CChange(StringBuilder ssb2)
    {
        ssb2.Append(" world");
        ssb2 = null;
    }
 
    static void Change(int b)
    {
        b = 10;
    }
Value types:

int, etc..

Reference types

Arrays eg int[]

List<T>

Class, Interface, Delegate and Array types are all reference types.

Immutable Reference Types:

string

| | # 
# Sunday, 13 December 2009

 

On overloaded constructors, call the default constructor.  Constructor chaining

public clsDates(int yr) : this()

public clsDates()

Property Methods (getters and setters)

Cohesion – make a method do a single task only

Coupling - (Method coupling) ability to make changes in one method without forcing changes in another… ie make each method so it can operate independently

Deck of Cards

image

I’ve simplified the example given in the book to:

private void btnShuffle_Click(object sender, EventArgs e)
    {
        clsCardDeck myDeck = new clsCardDeck();
        int numberOfIterations = myDeck.ShuffleDeck();
        lblResult.Text = numberOfIterations.ToString();
 
        // display the newly shuffled deck in the multiline textbox.
        int deckSize = myDeck.DeckSize;
        for (int i = 1; i < deckSize+1; i++)
        {
            txtOutputResult.Text += myDeck.getOneCard(i) + " ";
        }
    }
 
then for clsCardDeck
 
public int ShuffleDeck()
{
    int index;
    int val;
    Random rnd = new Random();
    passCount = 0; // count how many times through the while loop
    index = 1;
    Array.Clear(deck, 0, deck.Length); // initialise the deck array to 0's
 
    while (index < deck.Length) // loop probably 52 times.. initialised at the top of this class.
    {
        // add 1 to the offset 0-based array
        val = rnd.Next(DECKSIZE) + 1; // Generates values between 1 - 52
        if (deck[val] == 0) // Is this card place in the deck "unused"?
        {
            deck[val] = index; // yep, so assign it a card place.. ie put the index number into a random spot
            index++; // get ready for the next card
        }
        passCount++;
    }
    return passCount;
}
 
/// <summary>
/// Show a given card in the deck
/// </summary>
/// <param name="index">the index of the position where the card is found</param>
/// <returns>the pip for the card, or empty or error</returns>
public string getOneCard(int index)
{
    if (index > 0 && index <= deck.Length && nextCard <= deck.Length)
        return pips[deck[index]]; // returns the 6H style string of the deck.
    else
        return ""; // error
}

Sideways Refinement:

1. Initialize – build and display the main form (frmDave)

2. Input – none

3. Process – Shuffle the deck (clsCardDeck)

4. Display – Show deck on 4 rows (frmDave) –> which uses Get One Card at a Time (clsCardDeck)

Clear Deck (frmDave)

5. Terminate – Close (frmDave)

this helped in thinking which class had which responsibilites.

InBetweenGame

You deal 2 cards, then bet on the outcome of the hidden 3rd card. Shown below I bet on a card coming up between 9D and QS.  It was a 3H, so I lost.

Debug information is in the textbox to the right hand side.

Source here

image

The architecture uses a middle ‘tier’ of rules, and a CardDeck class as used above.

Sideways Refinement:.. showing the responsibilities of each class.  Very useful.

1. Initialise – build and display the form (frmMain) – get initial wager and balance (clsRules)

- Do initial shuffle (clsCardDeck)

2. Input – get amount of wager (frmMain)

- ask for new cards.. deal.. (frmMain)

- ask for bet (frmMain)

3. Process – deal a hand (rules)

- enough money to bet (frmMain)

- enough cards in deck (clsCardDeck)

- no? shuffle (clsCardDeck)

- Get three cards (clsRules)

- Figure out winner and position to display card (clsRules) **note here it knows the winner after deal button is pressed

- make a bet (frmMain)

4. Display - display if TIE, WIN, LOSE message and adjust balance (frmMain)

- display card in correct position (frmMain)

5. Terminate – Close

This was interesting code:.. see post on this blog on Parameter Passing in C#.

// get three cards, result, and position to display
 // nb cards is a reference type (all arrays are), so don't need a ref.. it will be changed here.
 myRules.DealHand(cards, ref betResult, ref position);
| | # 
# Friday, 11 December 2009

Continuing in the book series.

Part III, Chapter 9 – Designing Classes

Major benefits from OOP

  • Data encapsulation
  • Code reuse

Write a class that determines the date of Easter, and whether it is a leap year.

5 Programming Steps:

  1. Initialization
  2. Input
  3. Process
  4. Display
  5. Terminate
UML Light and Static

- daysInMonth : static int[]

// regardless of how many instances of this class you create, you get only one array named daysInMonth.

// the – means it is private..

// properties.. generally we want to hide as much as possible.

Use static with any data that can be shared between instances of classes

or any data that must be present the moment the program is ready to start executing

Code is here

image

This is how the author likes to set out his classes..

using System;
 
public class clsDates
{
    // PROPERTIES
    // symbolic constants
    // static members
    static int[] daysInMonth = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
 
    // instance members.. this is the common term for all non-static properties.
    int day;
    int month;
    int year;
    int leapYear;
    DateTime current;
 
    //METHODS
    // constructor
    public clsDates()
    {
        current = new DateTime();
    }
 
    // property methods
    // helper methods
    // general methods
 
    /// <summary>
    /// Purpose:  To determine if the year is a leap year.
    /// </summary>
    /// <param name="year">the year under construction</param>
    /// <returns>1 if a leap year, 0 otherwise</returns>
    public int getLeapYear(int year)
    {
        if (year % 4 == 0 && year % 100 != 0 || year % 400 == 0)
            return 1; // it is a leap year
        else
            return 0;
    }
 
    /// <summary>
    /// To determine the date for Easter given a year
    /// </summary>
    /// <param name="year">int year - the year under construction</param>
    /// <returns>the date in DateTime as MM/DD/YYYY format</returns>
    public string getEaster(int year)
    {
        int offset;
        int leap;
        int day;
        int temp1;
        int temp2;
        int total;
 
        offset = year % 19;
        leap = year % 4;
        day = year % 7;
        temp1 = (19 * offset + 24) % 30;
        temp2 = (2 * leap + 4 * day + 6 * temp1 + 5) % 7;
        total = (22 + temp1 + temp2);
        if (total > 31)
        {
            month = 4; // Easter is in April
            day = total - 31; // on this day
        }
        else
        {
            month = 3; // Easter is in March
            day = total; // on this day
        }
        DateTime myDT = new DateTime(year, month, day);
        return myDT.ToLongDateString();
    }
}

I loved his irreverant style Exercises:

Q: Give a good example of where you would use the public access specifier to define a class property?

A: I couldn’t think of one either :-)

SOC = Show Off Code :-)

| | # 
# Thursday, 10 December 2009

 

Chapter 8 – Arrays

Array cheat code:

string[] names = new string[10]; // this array can only have 10 elements
        names[0] = "Dave";
        names[1] = "Heidi";
        names[2] = "Scotty";
        for (int i = 0; i < 3; i++)
        {
            lstOutput.Items.Add(names[i].ToString());
        }

        int[] coolNumbers = new int[10] {1,2,5,7,11,13,17,19,23,27};  // initializing an array

        int[,] grades = new int[5,4]; // grades and which type eg Freshman, Sophmore, Junior, Senior
        grades[0, 0] = 1;
        grades[1, 0] = 4;

// Declare a single-dimensional array 
int[] array1 = new int[5];
 
// Declare and set array element values
int[] array2 = new int[] { 1, 3, 5, 7, 9 };
 
// Alternative syntax
int[] array3 = { 1, 2, 3, 4, 5, 6 };

Setting up a project template in Visual Studio.  Very useful if you don’t want a standard WinForms project etc.. to start with:

This is the way the book recommends starting a project.  Notice how few references, and we’re not using partial classes and  a seperate Program.cs file.  I like this method as it is keeping things very simple as easy to understand.

screen8

To export this as a template, go to File, Export as template.

Then to start a new project, do File, New then look for My Templates down the bottom..

screen10

Letter Count program

5 Steps

1) Initialisation

2) Input Step

  text is entered by the user

3) Process Step

  examine each letter types in the textbox and count how many times each alpha character occurs

4) Output Step

  Copy the letter counts to a listbox

5) Terminate

 

image

for (int i = 0; i < input.Length; i++) // loop over each letter in the input string
        {
            oneLetter = input[i]; // extract the letter we want to examine
            index = oneLetter - LETTERA; // taking int 65 away from a character
            if (index < 0 || index > MAXCHARS) // making sure range is between 0 and 25
                continue;
            count[index]++; // adding 1 to the count of the appropriate array
        }

The output to the listbox is interesting in the string.Format.

for (int i = 0; i < MAXLETTERS; i++)
        {
            // letter has 4 spaces and is right justified
            // space has 20
            // count is just displayed
            buff = string.Format("{0, 4} {1,20} {2} ", (char) (i + LETTERA), " ", count[i]);
            lstOutput.Items.Add(buff);

ListView

Displaying formatted lists is very common, so there is special control for doing this:

image

Go to columns.. and also change view to details, so the column headers are displayed on the output.

image

 

Multidimensional Arrays

image

int[,] myData = new int[number, 3];  // create new array with 3 dimensions

// Program and Display
for (int i = 0; i < number; i++)
{
    myData[i, 0] = i;
    myData[i, 1] = i*i;
    myData[i, 2] = i*i*i;
}

Collections

A collection is a set of objects which share the same characteristics eg strings

image

int[] days = new int[] {0,31,28,31,30,31,30,31,31,30,31,31 };        
string[] weekDays = new string[] {"Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"}; 

foreach (string str in weekDays) 
{ 
 lstOutput.Items.Add(str); 
} 

 foreach (int val in days) 
 { 
   lstOutput.Items.Add(val); 
 }

Because arrays are objects, you can treat them as a collection and iterate over them with a foreach loop.

ArrayList

You can’t use a static array until it’s dimension has been set eg

string[] names = new string[100]  // this can hold 100 names, and no more!

image

ArrayList names = new ArrayList();

names.Add(txtName.Text);

Static multiarray, using ListView

Ch9IdealWeights

image

 

Random Values and Sorting

image

Uses a list box which is populated by a 1 dimensional array of random numbers

Sorting is done via:

Array.Sort(arrayOfNumbers);

Random Values and Stars

RandomValues VS2008 source

image

I built the stars using a loop.  However a better solution is:

string stars = “**********************************************************************”

stars.Substring(0, howeverManyYouWant)

this was what I had:

  1. // add appropriate number of start to the end of the string.
  2.             int actualNumber = arrayOfNumbers[i];
  3.             string stars = "";
  4.             // build the number of stars
  5.             for (int j = 1; j <= actualNumber; j++)
  6.             {
  7.                 stars += "*";
  8.             }
  9.             
  10.             string output = actualNumber.ToString() + stars;
  11.             lstResults.Items.Add(output);
| | # 
# Wednesday, 09 December 2009

 

beginning

This book looked interesting as it seemed to be written by someone with a lot of experience teaching.  Sometimes it is great to go back to basics, as there is always something new to learn, and I was so right!  Here are my notes, source code, screenshots.

Chapter 1 – Getting Started

setting up the IDE.. VS2008 Express.   And installing the MSDN library.. 2GB download here: http://www.microsoft.com/downloads/details.aspx?FamilyID=7BBE5EDA-5062-4EBB-83C7-D3C5FF92A373&displaylang=en

Also a tool to take msdn into a chm help file: http://www.codeplex.com/packagethis

Chapter 2 - Understanding Objects

Class eg Person.. a template used to describe an object
  properties..that describe the object
  methods.. or actions that we associate with the object

Object eg the Person Object for Jack

naming convention
  cls - class
  txt - textbob
  btn - button

  good for selecting in the ide

making a blank project
putting in references for winform:

System, System.Drawing, System.Windows.Forms

putting in bootstrapper
change output to winform and tell which startup object asdf

using System;
using System.Windows.Forms;

public class frmMain : Form
{
    #region Windows code
    private void InitializeComponent()
    {
    }
    #endregion

    public frmMain()
    {
        InitializeComponent();
    }

    public static void Main()
    {
        frmMain main = new frmMain();
        Application.Run(main);
    }

}

3d on labels cool
making a default enter button (acceptbutton)
ctrl x and ctrl d shortcut keys with the ampersand on Text
True Type vs non fonts.. good to make things line up properly.

**screenshot mailing label program

**source code here too … c:\code\oopbook

screen

 

Part II – Understand C# Syntax

Chapter 3 – Understanding Data Types

Integer Division
.Focus property when coming back from an error
Int.TryParse method to see if it really is an integer
.Visible proerty of a textbox

Floating Point
AcceptButton
StartPosition - CenterScreen

int
float - 32 bit.. F,f
double - 64 bit... this is the usual one.. D,d
Decimal - 128bit (28 digit precision)..  M,m

eg int i = 0.5M

**insert source code  c:\code\oopbook\ch3IntegerDivision\

screen1

Also Fahrehiegh converter:

** put in source code link… c:\code\oopbook\ch3TempConvert

screen2

Interesting here was the use of consts…

how a division takes up more cycles, so better not to do 5/9 but to put in the decimal equivalent.  The out.. focus when  coming back from an error.  And unhiding the results box when it needs to be.

bool flag;
        double operand1;
        double answer;
        const double FIVENINTHS = 0.55555555;
        const double ZEROFAHRENHEIGHT = 32;

        flag = double.TryParse(txtOperand1.Text, out operand1);
        if (flag == false)
        {
            MessageBox.Show("Enter a whole number", "Input Error");
            txtOperand1.Focus();
            return;
        }

        answer = FIVENINTHS *(operand1 - ZEROFAHRENHEIGHT);

        txtResult.Text = operand1.ToString() + " degressF "  + " equals " + answer.ToString() + " degreesC";
        txtResult.Visible = true;

Ch4 – Understanding C# Statements

operand   eg 10
operator eg +, -, *, /, % these are binary operators
  unary
  binary
  ternary

expression
  one or more operands and their associated operator

statements
  one or more expressions terminated by a semicolon.

lvalue - location value.. memory address
rvalue - register value..actual value

eg int i
this is defining a variable to be at address 900,000 ie lvalue
i = 10
this is declaring a variable to have an rvalue of 10

if narly bug, hardcode data into the textboxes to make it easy!
10 / 6

avoid magic numbers
use const

Ch5 - Reference Data Types

If you're not going to manipulate data with Maths, store it as a string.

intellisense (expect in Resharper which is clearer)
  hand is a property
  diamond is a method

Pass by reference vs Pass by Value

Ctrl spacebar to give help on methods/props near current selection.

**insert source…c:\code\oopbook\ch5StringTester

screen3

Escape characters eg string message = “this is a \\ backlash, and this is a quote \””;

String literals eg string message = @”Go the the c:\program files\ directory and”;

DateTime reference Objects

**upload source code** c:\code\oopbook\ch5DateTime

screen4

Interesting code here is:

txtLongDate.Text = myTime.ToString("D");

Starting the app (everything gets populated automatically without having to press Test)

public frmMain()
{
    // 2) place all the label, textbox and button objects in correct positions on the form and set their properties
    InitializeComponent(); 
    UpdateTimeInfo();  // 3) set the properties of the objects just created
}

public static void Main()
{
    // 1) start here then this goes to constructor now everything is in memory ready to go
    frmMain main = new frmMain(); 
    Application.Run(main);  // 4) run the app
    MessageBox.Show("hello"); // 5) this would only be displayed when Close() is called.
}

Ch6 – Making Decisions In Code

20% of a programs time is spent in initial development

80% of a programs time is spent in testing, debugging, and maintenance

flag = int.TryParse(txtOperand1.Text, out operand1);

don’t need to initialise operand1 to any value.. int operand1 is fine.

**upload code ** c:\code\oopbook\ch6OddOrEven

screen5

Interesting here is the .Clear method after the check.

MessageBox.Show("Enter a whole number", "Input Error");
        txtOperand1.Clear();
        txtOperand1.Focus();
        return;

Brackets Style:

K&R (Kernighan and Ritchie… 1978 book on C)

if (x == 2) {

//do something

}

Other style:

if (x == 2)

{

  //do something

}

or

if (x == 2)

  // do something

the danger of the above is it’s easier to make a mistake like:

if (x == 2);  // notice the semicolon!

  //do something

Nested If Statements / Cascading if statements

Switch

statements are better

switch (expression1)

{

case 1:

// do stuff here

break;

case 2:

// do other stuff

break;

default:

// do the default stuff.

break;

}

Ch7 Statement Repetition Using Loops

screen1

for (i = start; i <= end; i++)
{
    // {0, 5} first argument and right-justify it in a field of five characters
    // {1,20} second argument and right-justify in a field of twenty characters
    buff = string.Format("{0, 5}{1, 20}", i, i*i);
    lstOutput.Items.Add(buff);
}

for loops – ideally suited for counting operations

while loops are good for searching for a particular value in a set

screen6

bucket = 1;
        for (int i = num; i > 1; i--)
        {
            bucket *= i;
        }

Don’t need to do the last factorial as it multiplies by 1, so leave i > 1.

Keyboard shortcut – F7 to view designer / view code

 

screen7

Notice the currency here:

buff = string.Format("{0,4}, {1,15:C}", i, assetIsWorth);
lblResults.Items.Add(buff);

http://www.programgood.net/2009/12/14/ParameterPassingInCValueAndReferenceTypes.aspx
| | # 
# Wednesday, 21 October 2009
Customer tests confirm how the feature is supposed to work as experienced by the end user.

Because customers generally don't want to use nUnit.. we're going to use Fitnesse, which is more user friendly:

The goal is to have the customer write their own tests.

To setup Fitnesse.  Download the .jar and run it like this:

c:\apps\fitnesse -jar fitness.jar -p 8080

Then go and get slim for .net.  I installed it to c:\apps\slim



Here is how it works for the Divider example:

!define TEST_SYSTEM {slim}
!define COMMAND_PATTERN {%m -r fitSharp.Slim.Service.Runner,c:\apps\slim\fitsharp.dll %p}
!define TEST_RUNNER {c:\apps\slim\Runner.exe}
 
!path C:\code\slimexample\slimexample\bin\Debug\slimexample.dll

|import      |
|slim_example|

!|Divider|
|Numerator|Denominator|Quotient?|
|10       |2          |5      |
|12.6     |3          |4.2      |
|22       |7          |~=3.14   |
|9        |3          |<5       |
|11       |2          |4<_<6    |
|100      |4          |33       |

Here is the C# code, I compiled to slimexample.dll
using System;

namespace slim_example
{
    public class Divider
    {
        public double  Numerator { get; set; }
        public double Denominator { get; set; }
        double _quotient;

        public void Execute()
        {
            _quotient = Numerator / Denominator;
        }

        public double Quotient()
        {
            return _quotient;
        }
    }
}
Run the tests.. and we'll see that when 2 numbers are sent... then then ? in the Fitnesse means that something should be checked.


Then we wire up to our code and test CatalogAdapter:

From this test we can see that I've a bug.. something wrong with the Duration.



Debugging

Have been working through why we are not getting the duration through.  The unit tests on the DAL are passing fine.. in CatalogFixture, have added in 2 tracks of different lengths.  They get pushed into the db, then pulled out using Catalog.. looks ok.



The next step is to look at the Service layer and see if the Duration is being written.  Interestingly, the webservice is passing back all the correct tracks, but nothing to do with reviewers etc..




Very interesting bug.. if I didn't specify this in my RecordingAssembler.WriteTotalRunTime:

dto.totalRunTimeSpecified = true;

then nothing would be passing back.  Same for WriteAverageRating.


Came across another issue with the webservice, and couldn't get it to autogen.. easiest way was to create it again.  Using source control so it if all went to custard, could go back.

Been getting bogged down in detail, so have decided to push to the end of the project, and get a front end up and running asap.



| | # 
# Tuesday, 20 October 2009
Task:  create a WebService that returns a recording and all its entities when specifying the id of the recording. Return type of XML (ie not a .net dataset).

The DAL.Catalog returns a RecordingDataSet.Recording.

We need to write a DTO that takes an input and transforms(munges) it into something else

Using a Service Interface Pattern.

Build a stub, map it into a DTO, and verify each field.
First thing I did was to create a stub, to hide how the RecordingDataSet is retrieved..so am not relying on the DAL at this point.

Here is the test the Stub code:
[TestFixture]
  public class CatalogServiceStubFixture
     {
         RecordingDataSet.Recording recording;
         RecordingDataSet.Recording actual;
         CatalogServiceStub service;
 
         [SetUp]
         public void SetUp()
         {
             // create a test recording in memory
             recording = CreateRecording();
             service = new CatalogServiceStub(recording);
             actual = service.FindByRecordingId(recording.Id);
         }
 
         private RecordingDataSet.Recording CreateRecording() 
         {
             RecordingDataSet dataSet = new RecordingDataSet();
             RecordingDataSet.Recording recording = dataSet.Recordings.NewRecording();
             recording.Id = 1;
            // more code needed here to fill in the rest of the recording.
             return recording;
         }
 
         [Test]
         public void CheckId()
         {
             Assert.AreEqual(recording.Id, actual.Id);
         }

Next we want a dto to transform our dataset, into something else:



To specify in platform independant, we use XML.  This is still quite bulky, perhaps JSON would be lighter now.

<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:tns="http://nunit.org/webservices" elementFormDefault="qualified" targetNamespace="http://nunit.org/webservices" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="Recording" type="tns:RecordingDto" />
  <xs:complexType name="RecordingDto">
    <xs:sequence>
      <xs:element minOccurs="1" maxOccurs="1" name="id" type="xs:long" />
      <xs:element minOccurs="1" maxOccurs="1" name="title" type="xs:string" />
      <xs:element minOccurs="1" maxOccurs="1" name="artistName" type="xs:string" />
      <xs:element minOccurs="1" maxOccurs="1" name="releaseDate" type="xs:string" />
      <xs:element minOccurs="1" maxOccurs="1" name="labelName" type="xs:string" />
      <xs:element minOccurs="0" maxOccurs="unbounded" name="tracks" type="tns:TrackDto" />
      <xs:element minOccurs="0" maxOccurs="unbounded" name="reviews" type="tns:ReviewDto" />
      <xs:element minOccurs="0" maxOccurs="1" name="totalRunTime" type="xs:int" />
      <xs:element minOccurs="0" maxOccurs="1" name="averageRating" type="xs:int" />
    </xs:sequence>
  </xs:complexType>
  <xs:complexType name="TrackDto">
    <xs:sequence>
      <xs:element minOccurs="1" maxOccurs="1" name="id" type="xs:long" />
      <xs:element minOccurs="1" maxOccurs="1" name="title" type="xs:string" />
      <xs:element minOccurs="1" maxOccurs="1" name="artistName" type="xs:string" />
      <xs:element minOccurs="1" maxOccurs="1" name="duration" type="xs:string" />
      <xs:element minOccurs="1" maxOccurs="1" name="genreName" type="xs:string" />
    </xs:sequence>
  </xs:complexType>
  <xs:complexType name="ReviewDto">
    <xs:sequence>
      <xs:element minOccurs="1" maxOccurs="1" name="id" type="xs:long" />
      <xs:element minOccurs="1" maxOccurs="1" name="reviewerName" type="xs:string" />
      <xs:element minOccurs="1" maxOccurs="1" name="rating" type="xs:int" />
      <xs:element minOccurs="1" maxOccurs="1" name="reviewContent" type="xs:string" />
    </xs:sequence>
  </xs:complexType>
</xs:schema>


A benefit is that we can create C# from this:.. but really just getters and setters.  See below.. this led to an interesting bug.

http://www.codingday.com/xml-c-class-generator-for-c-using-xsd-for-deserialization/

xsd asdf.xml - create an xsd
xsd asdf.xsd /CLASSES  - creates a .cs

Then just creating an 'Assembler', which writes out the DTO...(from http://martinfowler.com/eaaCatalog/dataTransferObject.html)

The Assembler has business logic in it to flatten the structure (as in the similar example above)

The webservice is setup by adding it into IISAdmin.

As the default ASP.NET user does not have access to my local database
connection = new SqlConnection("Data Source=DAVEXPLAPTOP;Initial Catalog=catalog;Integrated Security=True");

The easiest way to get running on dev was to add the DAVEXPLAPTOP\ASPNET user into my SQL database.  This didn't show up under objects when adding, but I went ahead anyway and it worked.







So this is what we have so far:


| | # 
From the nbdn course, I had some interesting code I'd like to test.  Just the business logic really, no DAL nor UI.  As I wanted to make a full application, the first though was to make a DAL which talked to a text file, or just some dummy data.  How to do this well?  De-coupled.  Tried to use poor mans dependency injection, and got confused.  So I had a coffee, and bought this book.  Because it had an end to end example of a testable application.  It uses .net1.1 mostly (which is good as there are no language constructs to learn)



Some good introduction to refactorings, and unit testing.  The main meat of the book is an example called MediaLibrary (music recordings).  Chapter 5 started with testing the DAL.

Here are the first tests.  Am showing nunit test runner.. mostly I use testdriven.net, and have setup ctrl alt shft t to run tests.



for source control I'm using  git, and have coupled up with gvim as text editor.  And linked in beyond compare for a merge tool.

The book uses Strongly Typed Datasets, which were the 'star of the show' in the .net1.0 release.  By writing the sql, and having intellisense have autoproperties, this saves writing boiler plate code.

I learned about DataSets.. here is my edit (from wikipedia)..http://en.wikipedia.org/wiki/ADO.NET#DataSets

ADO.NET consists of two primary parts:

Data provider

These classes provide access to a data source, such as a Microsoft SQL Server.  Each data source has its own set of provider objects, but they each have a common set of utility classes:

  • Connection: Provides a connection used to communicate with the data source.
  • Command: Used to perform some action on the data source, such as reading, updating, or deleting relational data.
  • Parameter: Describes a single parameter to a command. A common example is a parameter to a stored procedure.
  • DataAdapter: A bridge used to transfer data between a Data source and a DataSet object (see below).
  • DataReader: Used to efficiently process a large list of results one record at a time. It allows records to be accessed in a read-only, forward-only mode, i.e., records have to be accessed in sequential order; they can neither be randomly accessed nor can a record which has been processed previously be accessed again.

DataSets

DataSet objects, a group of classes describing a simple in-memory relational database,

  • A DataSet object represents a schema (either an entire database or a subset of one). It can contain tables and relationships between those tables.
    • A DataTable object represents a single table in the database. It has a name, rows, and columns.
      • A DataView object overlays a DataTable and sorts the data (much like an SQL "order by" clause) and filters the records (much like an SQL "where" clause) if a filter is set. An in-memory index is used to facilitate these operations. All DataTables have a default filter, while any number of additional DataViews can be defined, reducing interaction with the underlying database and thus improving performance.
        • A DataColumn represents a column of the table, including its name and type.
        • A DataRow object represents a single row in the table; it allows reading and updating of values in that row, likewise retrieving any rows that are related to it through a primary-key foreign-key relationship.
VS has a nice editor:



Once I spiked up what datasets were (in simpleDatabaseTests.cs).. used this for reference: http://www.csharp-station.com/Tutorials/AdoDotNet/Lesson05.asp
 [Test]
        public void put_data_into_a_dataset()
        {
            DataSet dataset = new DataSet();
            SqlDataAdapter data_adapter = new SqlDataAdapter("select id, name from Artist", connection);
            SqlCommandBuilder sql_command_builder = new SqlCommandBuilder(data_adapter);
            data_adapter.Fill(dataset, "Artist");
            Assert.IsNotNull(dataset);

            DataTable data_table = dataset.Tables[0];
            for (int i = 0; i < data_table.Rows.Count; i++)
            {
                DataRow data_row = data_table.Rows[i];
                Console.Out.Write(data_row["id"] + " ");
                Console.Out.WriteLine(data_row["name"]);
            }
        }

The example I'm working through uses a Table Data Gateway Pattern for the DAL. 

http://martinfowler.com/eaaCatalog/tableDataGateway.html
"A Table Data Gateway holds all the SQL for accessing a single table or view: selects, inserts, updates, and deletes. Other code calls its methods for all interaction with the database."

Lets take an example of ArtistFixture.cs which tests ArtistGateway.cs

[TestFixture]
    public class ArtistFixture
    {
        static readonly string artistName = "Artist";
        SqlConnection connection;
        ArtistGateway gateway;
        RecordingDataSet recordingDataSet;
        long artistId;

        [SetUp]
        public void setup_and_open_connection_pass_to_gateway_setup_data_set()
        {
            connection = new SqlConnection(ConfigurationSettings.AppSettings.Get("Catalog.Connection"));
            connection.Open();

            recordingDataSet = new RecordingDataSet();
            gateway = new ArtistGateway(connection);
            // insert a new artist getting its ID from the database
            artistId = gateway.Insert(recordingDataSet, artistName);
        }

        [Test]
        public void RetrieveArtistFromDatabase()
        {
            // create new RDS, use same gateway.
            RecordingDataSet loadedFromDB = new RecordingDataSet();
            RecordingDataSet.Artist loadedArtist = gateway.FindById(artistId, loadedFromDB);

            Assert.AreEqual(artistId, loadedArtist.Id);
            Assert.AreEqual(artistName, loadedArtist.Name);
        }
Here is part of ArtistGateway.cs.. gateway is newed up with a connection passed in.. then only in Insert is it passed in a strongly typed RecordingDataSet, which has all the SQL in it which has been auto-genned.
public class ArtistGateway
{
SqlDataAdapter adapter;
SqlConnection connection;
SqlCommand command;
SqlCommandBuilder builder;

public ArtistGateway(SqlConnection connection)
{
this.connection = connection;

command = new SqlCommand("select id, name from artist where id = @id",connection);
command.Parameters.Add("@id", SqlDbType.BigInt);

adapter = new SqlDataAdapter(command);
builder = new SqlCommandBuilder(adapter);
}


public RecordingDataSet.Artist FindById(long artistId, RecordingDataSet recordingDataSet)
{
command.Parameters["@id"].Value = artistId;
adapter.Fill(recordingDataSet, recordingDataSet.Artists.TableName);
DataRow[] rows = recordingDataSet.Artists.Select(String.Format("id={0}", artistId));

if (rows.Length < 1) return null;
return (RecordingDataSet.Artist) rows[0];
}
Class Diagram done in VS2008 with the Class Designer Powertoy http://www.codeplex.com/modeling
To get the blue lines go to Class Diagram, Filter Lines, Show All Associations.

Sequence diagram done in Visio: (hmm - this is a bit complex... I prefer the class diagram above with notes)


Genre was next, then the rest.  Then relationships between objects eg ReviewReviewer.. just testing the test data we create comes back:  Have abstracted out some of the setup code into ConnectionFixture.
 [TestFixture]
 public class ReviewReviewerFixture : ConnectionFixture
 {
     [Test]
     public void ReviewerId()
     {
         RecordingDataSet recordingDataSet = new RecordingDataSet();

         ReviewGateway reviewGateway = new ReviewGateway(Connection);
         long reviewId = reviewGateway.Insert(recordingDataSet, 1, "Review Content");

         ReviewerGateway reviewerGateway = new ReviewerGateway(Connection);
         long reviewerId = reviewerGateway.Insert(recordingDataSet, "Reviewer Name");

         RecordingDataSet.Review review = reviewGateway.FindById(reviewId, recordingDataSet);

         review.ReviewerId = reviewerId;
         reviewGateway.Update(recordingDataSet);

         Assert.AreEqual(reviewerId, review.Reviewer.Id);

         reviewGateway.Delete(recordingDataSet, reviewId);
         reviewerGateway.Delete(recordingDataSet, reviewerId);
     }
 }
The hardest test is RecordingGateway, as it depends on all the other 'tables'.  To simplify, we abstract out the insert/del of test data to RecordingBuilder.cs.

The last class is Catalog, which is the only class that will be called from the Service layer.  In Catalog we have FindByRecordingId, which returns a RecordingDataSet.Recording (so all the data associated with this recordingId).




In summary we have done this of the overall structure of the APP:

| | # 
# Friday, 09 October 2009
JP Boodhoo's Nothing But Dot Net Bootcamp (Sydney)


A mindblowing (melting) experience.  The overall summary of what I learned, is that I know where I want to go now.  Can see how I'd like to develop.

A great series of articles on what we did:
http://www.davesquared.net/2009/08/nothin-but-net-sydney-2009-day-1.html

Xerxes video discussing the camp:
http://ozalt.net/blog/virtual-alt-net-aug-17-jp-boodhoo-s-bootcamp/

Over the last year I've started using:

gvim - text editor (still getting used to it!)
git - source control
gmail - learned the keyboard shortcuts which has been amazing
launchy - quick launcher
vs2008 - black colour of fonts, class diagram
resharper - auto formatting of doc, easily navigate large codebases, refactorings, moving code, create classes quickly
console2 with powershell - use it for git, navigating between projects
windows - keyboard shortcuts like windows file exploring tabbing around
firefox 3.5 with vimperator extensions
beyond compare - easily put stuff live
alt tab replacement
balsamiq - for mocking up UI's
sdedit  - for doing sequence diagrams


Goal over the next 2 months is to write an application in a well architected manner. 

Am starting with the MovieLibrary example (it could be used to catalog your home movies) we worked on at nbdn.  Basically putting a front end, and a DAL on the existing code..

Biggest lessons I've learned this year are:

- have fun!
- to become a great develop you need to code, code, code <grin>



| | # 
# Saturday, 01 August 2009
Interesting..added in C#2.0

using System;
using System.Collections.Generic;

class Program
{
    static void Main(string[] args)
    {
        // enumerates through the IEnumerable
        // every time call GetInt() we receive a new incremented integer
        foreach (int i in GetInt())
            Console.WriteLine("Got " + i.ToString());
    }

    public static IEnumerable<int> GetInt()
    {
        // this method remembers its' state, so every time it is called, 
        // the next int is returned
        for (int i = 0; i < 5; i++)
            yield return i;
    }
}
thanks to: http://www.c-sharpcorner.com/UploadFile/rmcochran/yieldreturn04022006113850AM/yieldreturn.aspx?ArticleID=4617984b-2209-4211-9d08-8f06e0fe2da5

| | # 

From: http://msdn.microsoft.com/en-us/library/bb383977.aspx

Extension methods enable you to "add" methods to existing types without creating a new derived type,

Extension methods are a special kind of static method, but they are called as if they were instance methods on the extended type.

For client code, there is no apparent difference between calling an extension method and the methods that are actually defined in a type.

using System;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            string s = "hello extension methods are good";
            Console.WriteLine(s);
            int i = s.WordCount();
            Console.WriteLine("number of words is {0}", i.ToString());
        }
    }

    public static class MyExtensions
    {
        public static int WordCount(this String str)
        {
            return str.Split(new char[] { ' ', '.', '?' }, StringSplitOptions.RemoveEmptyEntries).Length;
        }
    }
}

| | # 
# Monday, 27 July 2009
Thanks to:
http://davidhayden.com/blog/dave/archive/2006/05/28/2974.aspx

Anon methods, delegates, predicates.  Anon methods are simple shortcuts so don't have to declare a predicate method.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace TestAnonymousMethods
{
    public class Program
    {
        // using an anon method
        static void Mainx(string[] args)
        {
            int[] _integers = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

            int[] evenIntegers = Array.FindAll(_integers,
                                        // this is the anonymous method below
                                       delegate(int integer)
                                       {
                                           return (integer % 2 == 0);
                                       }
                );

            foreach (int integer in _integers) 
                Console.WriteLine(integer);

            foreach (int integer in evenIntegers)
                Console.WriteLine(integer);
        }

        // not using anon method
        static void Mainy(string[] args)
        {
            int[] _integers = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

            // passing in IsEven..a delegate which represents the IsEven method
            int[] evenIntegers = Array.FindAll(_integers, IsEven);

            foreach (int integer in _integers)
                Console.WriteLine(integer);

            foreach (int integer in evenIntegers)
                Console.WriteLine(integer);
        }

        static bool IsEven(int integer)
        {
            return (integer % 2 == 0);
        }


       
        // not using anon method and looking at predicate / delegate of Array.FindAll
        static void Main(string[] args)
        {
            int[] _integers = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
            // a predicate is expected
            // passing in IsEven..a delegate which represents the IsEven method
            int[] whatIsInBoth = Array.FindAll(_integers, IsDaveSequence);

            foreach (int integer in whatIsInBoth)
                Console.WriteLine(integer);

        }

        static bool IsDaveSequence(int integer)
        {
            bool returnState = false;
            if ((integer == 1) || (integer == 3) || (integer ==4))
                returnState = true;
            return returnState;
        }



    }
}

| | # 
# Thursday, 23 July 2009
Delegates, delegate to another method.  In this example, depending on which person is wired up - Suzanne or Amy.. depends on which method is called when the Get the ingredient button is called.


source code here..delegateIngredients.zip (91.58 KB)






    // can be used to create a variable that can point to any method that takes an int parameter and returns a string
    public delegate string GetSecretIngredient(int amount);

On the form:
        // so variable ingredientMethod of type delegate GetSecretIngredient currently points to a null method
        GetSecretIngredient ingredientMethod = null;
        private void getSuzanne_Click(object sender, EventArgs e)
        {
            // suzanne.MySecretIngredientMethod property returns a new instance of the the GetSecretIngredient delegate thats
            // pointing to her secret ingredient method.
            ingredientMethod = new GetSecretIngredient(suzanne.MySecretIngredientMethod);
        }
When button is pressed it will go to either the suzanne.MySecretIngredientMethod or the amy.AmySecretIngredientMethod
        private void useIngredient_Click(object sender, EventArgs e)
        {
            if (ingredientMethod != null)
                Console.WriteLine("I'll add " + ingredientMethod((int)amount.Value));
            else
                Console.WriteLine("I dont have a secret ingredient");
        }
Good duck example here:
http://stackoverflow.com/questions/687626/the-purpose-of-delegates



| | # 
# Friday, 17 July 2009
A simple MVC (Model View Controller) implementation..code by Jimmy Chandra
http://stackoverflow.com/questions/1107720/mvc-c-simplest-possible-implementation

Why use MVC?  Similar reasons to MVP - testability and seperation of concerns

Simple.MVC.zip (167.25 KB)



1. Program.cs runs, running Main.. as is standard in a Win Forms app.  Difference from MVP is that main here is instantiating and running a controller class first of all, instead of newing up the view, which calls the controller/presenter.
static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            
            TopEmployeeController controller = new TopEmployeeController();
            Application.Run(controller.View as Form);
        }
2. Controller is instantiated and constructor called:
        private ITopEmployeeView _view;
        private Employee _employee;

        private bool _monitoring;

        public TopEmployeeController()
        {
            _employee = new Employee();
            _view = new TopEmployeeForm(this, _employee);
        }
3. Controller news up an employee (dumb).. then a view of type TopEmployeeForm, passing its self (the controller) and employee to it.

4. View (the observer) subscribes to the model (the subject) so that when model.OnPropertyChange is called, view.UpdateView is called.  This is the observer pattern, made easier in C# using events.. which is using a delegate.
// view
public TopEmployeeForm(ITopEmployeeController controller, Employee model)
        {
            _controller = controller;
            _model = model;

            //Let the model know that this view is interested if the model change
            _model.OnPropertyChange += new Action(UpdateView);

            InitializeComponent();
}
6. When Button is pressed on the view.  The controller.GetTopEmplyee method is called.  This calls model.MontorChanges:
// controller
public void GetTopEmployee()
{
if (!_monitoring)
{
_monitoring = true;
_employee.MonitorChanges();
}
}



7. MonitorChanges does some waiting code, then every second calls FirePropertyChange(). Which calls model.OnPropertyChange.
Which is really a delegate to View.UpdateView
// model
public event Action OnPropertyChange;

private void FirePropertyChange()
        {
            var propChange = OnPropertyChange;
            if (propChange != null)
            {
                OnPropertyChange();
            }
        }

8. The view method which runs every second and displays the name on the form.
// view
        public void UpdateView()
        {
            // to do with threading
            if (this.InvokeRequired)
            {
                this.Invoke(new Action(UpdateView));
            }
            else
            {
                TopEmployeeName = _model.FullName;
            }
        }




| | # 
# Friday, 03 July 2009
In preparation for JPBoodhoo's course in Sydney in a months time, I'm looking at the tooling he recommends and going through this videos on dnrtv.com

this is going to be an ongoing list of ideas for me refer to.. excuse the mess!

Setting up Subversion
http://www.west-wind.com/presentations/subversion/

Console2 - console with an alpha transparency
AltTab - alt tab replacement
Resharper4.5 - makes VS2008 faster
Testdriven.net - unit testing easier
mbunit - unit testing framework


Keyboard shortcuts

Testdriven.net - bound to  in VS2008, Tools, Options, Keyboard.  testdriven.net.runtests.. Ctrl-Shift-Alt-T
rerun tests is to testdriven.net.reruntest.. Ctrl-Shift-Alt-R

Resharper
Ctrl-Alt-v  - introduce variable (highlight and it gens the variable)
Alt-Int - generate constructor and..... from an interface
F2 - rename

| | # 
# Thursday, 09 April 2009
Why use Events or publish / subscribe?

Any number of classes can be notified when an event is raised.

The subscribing classes do not need to know how the Metronome works, and the Metronome does not need to know what they are going to do in response to the event

The publisher and the subscribers are decoupled by the delegate. This is highly desirable as it makes for more flexible and robust code. The metronome can change how it detects time without breaking any of the subscribing classes. The subscribing classes can change how they respond to time changes without breaking the metronome. The two classes spin independently of one another, which makes for code that is easier to maintain.



Example1 - Metronome
Create a new console app, paste in the Main() code.  Then create 3 new classes (Alt P, C) - Metronome, Listener, ListenerB
A metronome ticks every 2 seconds, and two objects 'hear' it:

class Program
{
    static void Main()
    {
        // setup the metronome and make sure the EventHandler delegate is ready
        Metronome metronome = new Metronome();

        // wires up the metronome_Tick method to the EventHandler delegate
        Listener listener = new Listener(metronome);
        ListenerB listenerB = new ListenerB(metronome);
        metronome.Go();
    }
}

public class Metronome
{
    // a delegate
    // so every time Tick is called, the runtime calls another method
    // in this case Listener.metronome_Tick and ListenerB.metronome_Tick
    public event EventHandler Tick;

    // virtual so can override default behaviour in inherited classes easily
    protected virtual void OnTick(EventArgs e)
    {
        // null guard so if there are no listeners attached it wont throw an exception
        if (Tick != null)
            Tick(this, e);
    }

    public void Go()
    {
        while (true)
        {
            Thread.Sleep(2000);
            // because using EventHandler delegate, need to include the sending object and eventargs 
            // although we are not using them
            OnTick(EventArgs.Empty);
        }
    }
}


public class Listener
{
    public Listener(Metronome metronome)
    {
        metronome.Tick += new EventHandler(metronome_Tick);
    }
    
    private void metronome_Tick(object sender, EventArgs e)
    {
        Console.WriteLine("Heard it");
    }
}

public class ListenerB
{
    public ListenerB(Metronome metronome)
    {
        metronome.Tick += new EventHandler(metronome_Tick);
    }
    
    private void metronome_Tick(object sender, EventArgs e)
    {
        Console.WriteLine("ListenerB: Heard it");
    }
}    
Example2 - MetronomeArgs
We are passing the current time from the Metronome to the 2 listener objects
static void Main()
{
    // setup the metronome and make sure the EventHandler delegate is ready
    Metronome metronome = new Metronome();

    // wires up the metronome_Tick method to the EventHandler delegate
    Listener listener = new Listener(metronome);
    ListenerB listenerB = new ListenerB(metronome);
    metronome.Go();
}

public class Metronome
{
    // a delegate
    // so every time Tick is called, the runtime calls another method
    // in this case Listener.metronome_Tick
    // so objects subscribing to this delegate should look like (object sender, EventArgs e)
    public event EventHandler Tick;
   
    // virtual so can override default behaviour in inherited classes easily
    protected virtual void OnTick(TickEventArgs e)
    {
        // null guard so if there are no listeners attached it wont throw an exception
        if (Tick != null)
            Tick(this, e);
    }

    public void Go()
    {
        while (true)
        {
            Thread.Sleep(2000);
            DateTime now = DateTime.Now;
            TickEventArgs tickEventArgs = new TickEventArgs(now);
            OnTick(tickEventArgs);
        }
    }
}


// Good idea to inherit from EventArgs
// as can upcast EventArgs object in case you need to send it to an event that doesn't handle it???
// sole purpose of EventArgs class (which has no members) is to allow event arguments object to be passed to 
// event handlers
public class TickEventArgs : EventArgs
{
    public DateTime Time { get; private set; }

    public TickEventArgs(DateTime time)
    {
        this.Time = time;
    }
}

public class Listener
{
    public Listener(Metronome metronome)
    {
        metronome.Tick += new EventHandler(metronome_Tick);
    }

    private void metronome_Tick(object sender, EventArgs e)
    {
        // TickEventArgs is a superclass(?) of EventArgs... this is what we passed
        if (e is TickEventArgs)
        {
            // Downcasting e from EventArgs to TickEventArgs so can use its properties
            TickEventArgs tickEventArgs = e as TickEventArgs;
            
            Console.WriteLine("Heard it at time " + tickEventArgs.Time.ToString());
        }
    }
}

public class ListenerB
{
    public ListenerB(Metronome metronome)
    {
        metronome.Tick += new EventHandler(metronome_Tick);
    }
    
    private void metronome_Tick(object sender, EventArgs e)
    {
        Console.WriteLine("ListenerB: Heard it");
        
    }
}
References:
Big thanks on: http://stackoverflow.com/questions/724085/events-naming-convention-and-style
Metronome code is refactored from http://www.codeproject.com/KB/cs/simplesteventexample.aspx
Why use events: http://www.akadia.com/services/dotnet_delegates_and_events.html

| | # 
# Wednesday, 25 February 2009


Thanks to the original author of the code (google m7tr1x)..

I had some great fun looking at the code, understanding how this effect works, and refactoring.

The original code is below.. I suggest scrolling down, and looking at the refactored code and pictures describing how the effect works.

Enjoy!

#define readkey

using System;

namespace m7tr1x
{
    class Program
    {
        static void Main(string[ ] args)
        {
            Console.Title = "tH3 M7tr1x 3ff3<t";
            Console.ForegroundColor = ConsoleColor.DarkGreen;
            Console.WindowLeft = Console.WindowTop = 0;
            Console.WindowHeight = Console.BufferHeight = Console.LargestWindowHeight;
            Console.WindowWidth = Console.BufferWidth = Console.LargestWindowWidth;
#if readkey
            Console.WriteLine("H1T 7NY K3Y T0 C0NT1NU3 =/");
            Console.ReadKey();
#endif
            Console.CursorVisible = false;
            int width, height;
            int[ ] y;
            int[ ] l;
            Initialize(out width, out height, out y, out l);
            int ms;
            while ( true )
            {
                DateTime t1 = DateTime.Now;
                MatrixStep(width, height, y, l);
                ms = 10 - (int)( (TimeSpan)( DateTime.Now - t1 ) ).TotalMilliseconds;
                if ( ms > 0 )
                    System.Threading.Thread.Sleep(ms);
                if ( Console.KeyAvailable )
                    if ( Console.ReadKey().Key == ConsoleKey.F5 )
                        Initialize(out width, out height, out y, out l);
            }
        }

        static bool thistime = false;

        private static void MatrixStep(int width, int height, int[ ] y, int[ ] l)
        {
            int x;
            thistime = !thistime;
            for ( x = 0 ; x < width ; ++x )
            {
                if ( x % 11 == 10 )
                {
                    if ( !thistime )
                        continue;
                    Console.ForegroundColor = ConsoleColor.White;
                }
                else
                {
                    Console.ForegroundColor = ConsoleColor.DarkGreen;
                    Console.SetCursorPosition(x, inBoxY(y[x] - 2 - ( l[x] / 40 * 2 ), height));
                    Console.Write(R);
                    Console.ForegroundColor = ConsoleColor.Green;
                }
                Console.SetCursorPosition(x, y[x]);
                Console.Write(R);
                y[x] = inBoxY(y[x] + 1, height);
                Console.SetCursorPosition(x, inBoxY(y[x] - l[x], height));
                Console.Write(' ');
            }
        }

        private static void Initialize(out int width, out int height, out int[ ] y, out int[ ] l)
        {
            int h1;
            int h2 = ( h1 = ( height = Console.WindowHeight ) / 2 ) / 2;
            width = Console.WindowWidth - 1;
            y = new int[width];
            l = new int[width];
            int x;
            Console.Clear();
            for ( x = 0 ; x < width ; ++x )
            {
                y[x] = r.Next(height);
                l[x] = r.Next(h2 * ( ( x % 11 != 10 ) ? 2 : 1 ), h1 * ( ( x % 11 != 10 ) ? 2 : 1 ));
            }
        }

        static Random r = new Random();
        static char R
        {
            get
            {
                int t = r.Next(10);
                if ( t <= 2 )
                    return (char)( '0' + r.Next(10) );
                else if ( t <= 4 )
                    return (char)( 'a' + r.Next(27) );
                else if ( t <= 6 )
                    return (char)( 'A' + r.Next(27) );
                else
                    return (char)( r.Next(32, 255) );
            }
        }

        public static int inBoxY(int n, int height)
        {
            n = n % height;
            if ( n < 0 )
                return n + height;
            else
                return n;
        }
    }
}
Here is the refactored code:
using System;

namespace matrix
{
    class Program
    {
        // fields
        static Random rand = new Random();
        
        // properties
        static char AsciiCharacter
        {
            get
            {
                int t = rand.Next(10);
                if (t <= 2)
                    // returns a number
                    return (char)('0' + rand.Next(10));
                else if (t <= 4)
                    // small letter
                    return (char)('a' + rand.Next(27));
                else if (t <= 6)
                    // capital letter
                    return (char)('A' + rand.Next(27));
                else
                    // any ascii character
                    return (char)(rand.Next(32, 255));
            }
        }

        // methods
        static void Main()
        {
            Console.ForegroundColor = ConsoleColor.DarkGreen;
            Console.WindowLeft = Console.WindowTop = 0;
            Console.WindowHeight = Console.BufferHeight = Console.LargestWindowHeight;
            Console.WindowWidth = Console.BufferWidth = Console.LargestWindowWidth;
            Console.WriteLine("Hit Any Key To Continue");
            Console.ReadKey();
            Console.CursorVisible = false;
            
            int width, height;
            // setup array of starting y values
            int[] y;

            // width was 209, height was 81
            // setup the screen and initial conditions of y
            Initialize(out width, out height, out y);

            // do the Matrix effect
            // every loop all y's get incremented by 1
            while ( true )
                UpdateAllColumns(width, height, y);
        }

        
        private static void UpdateAllColumns(int width, int height, int[] y)
        {
            int x;
            // draws 3 characters in each x column each time... 
            // a dark green, light green, and a space

            // y is the position on the screen
            // y[x] increments 1 each time so each loop does the same thing but down 1 y value
            for ( x = 0 ; x < width ; ++x )
            {
                // the bright green character
                Console.ForegroundColor = ConsoleColor.Green;
                Console.SetCursorPosition(x, y[x]);
                Console.Write(AsciiCharacter);

                // the dark green character -  2 positions above the bright green character
                Console.ForegroundColor = ConsoleColor.DarkGreen;
                int temp = y[x] - 2;
                Console.SetCursorPosition(x, inScreenYPosition(temp, height));
                Console.Write(AsciiCharacter);

                // the 'space' - 20 positions above the bright green character
                int temp1 = y[x] - 20;
                Console.SetCursorPosition(x, inScreenYPosition(temp1, height));
                Console.Write(' ');

                // increment y
                y[x] = inScreenYPosition(y[x] + 1, height);
            }

            // F5 to reset, F11 to pause and unpause
            if (Console.KeyAvailable)
            {
                if (Console.ReadKey().Key == ConsoleKey.F5)
                    Initialize(out width, out height, out y);
                if (Console.ReadKey().Key == ConsoleKey.F11)
                    System.Threading.Thread.Sleep(1);
            }

        }

        // Deals with what happens when y position is off screen
        public static int inScreenYPosition(int yPosition, int height)
        {
            if (yPosition < 0)
                return yPosition + height;
            else if (yPosition < height)
                return yPosition;
            else
                return 0;
        }

        // only called once at the start
        private static void Initialize(out int width, out int height, out int[] y)
        {
            height = Console.WindowHeight;
            width = Console.WindowWidth - 1;

            // 209 for me.. starting y positions of bright green characters
            y = new int[width];
            
            Console.Clear();
            // loops 209 times for me
            for ( int x = 0 ; x < width ; ++x )
            {
                // gets random number between 0 and 81
                y[x] = rand.Next(height);
            }
        }
    }
}

how it works:

The screen draws each column.. my screen is 208 wide.. so it loops 208 times, each time drawing a bright green character, dark green character, and a space.



The second loop.. the y value has been incremented by 1.



The 3rd loop



Enjoy!
| | #