Using C# for real

A year since playing with C# I've now deployed a real application! What difficulties did I have?

The Pitfalls

Here are some fragments from my "solution":

How to insert a parameterised row into an SQL database.

It took a long time to find a simple example!

using System.Data.SqlClient;

private
void insertResult(DateTime dt, int site_id, int tag, int direction, int slot, DateTime slottime)
{
    SqlConnection myConn =
new SqlConnection ("Data Source=Timmy;" +
                    "Integrated Security=SSPI;" + "Initial Catalog=test");

    string insertStr = "INSERT INTO Sightings (date_time, Site_id, tag, direction, slot, slot_time) " +
                        "Values(@date_time_XXX, @Site_id, @tag, @direction, @slot, @slot_time_XXX)";

    SqlCommand insertCMD = new SqlCommand(insertStr, myConn);

    insertCMD.Parameters.Add("@date_time_XXX", SqlDbType.DateTime).Value = dt;
    insertCMD.Parameters.Add("@Site_id", SqlDbType.Int).Value = site_id;
    insertCMD.Parameters.Add("@tag", SqlDbType.Int).Value = tag;
    insertCMD.Parameters.Add("@direction", SqlDbType.Int).Value = direction;
    insertCMD.Parameters.Add("@slot", SqlDbType.Int).Value = slot;
    insertCMD.Parameters.Add("@slot_time_XXX", SqlDbType.DateTime).Value = slottime;

    myConn.Open();
    Int32 recordsAffected = insertCMD.ExecuteNonQuery();
    myConn.Close();
// explicit - somewhat optional.
}

Time offsets

No examples - but obvious.

private void CalcSlotTime(DateTime dt, int slot, out DateTime slot_time)
{
    TimeSpan ts =
new TimeSpan(0,0,0,slot * 10, 0);
    slot_time = dt - ts;
}

Jagged Arrays

Who on Earth would want to use these? I immediately found a use for one in a character encoding lookup table:

char[][] myJaggedArray = new char[][]{
                                        new char[] {'B','V','Q','P','R'}, // 0
                                        new char[] {'A','E','F','S'},     // 1
                                        new char[] {'I','J','K','X'},     // 2
                                        new char[] {'H','D','G','O','U'}, // 3
                                        new char[] {'C','M','N','Z'},     // 4
                                        new char[] {'T','L','W','Y'},     // 5
};

(Don't try and guess what this table does - it's bogus anyway, even if you think you know what it is. So there!)

Coding with the jagged array:

Note the scoping of int a. It works correctly, unlike Microsoft's C++!

for (int a = 0; a < linear_array.Length; a++)
    linear_array[a] = -1;

for (int a = 0; a < myJaggedArray.Length; a++)
   
for (int b = 0; b < myJaggedArray[a].Length; b++)
    {
       
int c = myJaggedArray[a][b] - 'A';
        
       
if (c < 0 || c > 25)
           
throw(new ArgumentNullException()); // bail out!

        linear_array[c] = a;
    }

Strings

Objects, such as int, know how to represent themselves as strings. Very kind of them.

int num = 42;

string sz;
sz = "?";        
sz += num.ToString();            // decimal!
sz += num.ToString("x");        // hex!
sz += myJaggedArray[iA2][c];
sz += myJaggedArray[iA1][b];
sz += '?';

&& logical operator, the & bit-wise operator and "Short Circuit" evaluation

Of course we know all about bit-wise and logical operators don't we?

byte[] buffer = new byte[256];

long len = myReader.GetBytes(3,0,buffer,0,128);    // gets binary field from record

// check for Fat Boy Slim data - which we ignore

if (len == 8 && buffer[6] == 0xff && buffer[7] == 0xff)
   
continue;

I could write:

if (len == 8 & buffer[6] == 0xff & buffer[7] == 0xff)

There is an important difference. Using '&&' if "len == 8" is evaluated as false, the rest of the expression is ignored.

But with '&' if "len == 8" is evaluated as false, the rest of the expression is still evaluated.

Exceptions and Parsing Hex

try
{
   
int tag = Int32.Parse(s, System.Globalization.NumberStyles.HexNumber);
   
// other code deleted...
}
catch (InvalidCastException )
{
}
catch (FormatException)
{
    My_Diagnostics_list.Items.Add(@"There is a format problem with that hex entry. Tosser!");
}
finally
{
   
// come hell or high water, this code will be executed.
}

Structs and Classes

In C++ these are the same, with some differences to do with public, protected and private keywords. In C# they are different!

A struct is a value type, just like the various numeric types (int, enum, bool). Calling new on value type calls its constructor. Memory is not allocated by the new.

Here's a struct with a constructor and a member variable:

struct my_wee_struct
{
   
public my_wee_struct(int f){ s = f;}
   
public int s;
}

I can use this wondrous structure I've proudly created...

public Form1()
{
   
my_wee_struct nick = new my_wee_struct(42);
    Console.WriteLine(nick.s.ToString());
    ...
}

Nick is placed on the stack, not the heap, and is initialised when "newed" with the constructor.

If I substitute the keyword 'struct' with 'class'...

class my_wee_struct
{
   
public my_wee_struct(int f){ s = f;}
   
public int s;
}

.. All compiles as before, but now Nick is not on the stack: the new allocated memory from the heap. A Class is a reference type.

I can inspect the type I have at runtime by checking with: 

nick.GetType().IsValueType

This returns true if my_wee_struct is a struct, false if it's a class.

No problem. but...

The Gotcha with Structs and Classes

Here's a piece of code:

my_wee_struct nick = new my_wee_struct(42);
my_wee_struct andy = nick;
andy.s = 4000;
Console.WriteLine("{0}", nick.s);
Console.WriteLine("{0}", andy.s);

If my_wee_struct is a class the output is :
4000
4000

If my_wee_struct is a struct the output is :
42
4000

Note well: Class is a reference type. Struct is an value type. That's the difference!

Boxing

The above discussion on struct and classes leads us to Boxing. The behind your back conversion of a stack item to a heap item. 

Bill phases it a bit better: "Boxing is an implicit conversion of a value type to the type object."

Take WriteLine:

Console.WriteLine("{0}", nick);

This console method requires the second parameter to be an object. That is an argument that's lurking in the heap, not your stack.

This conversion may an overhead to concerned about - we'll see.

Beware the 'Save As'

If you choose to "Save As" your .cs file beware: The solution project will now chose to work with your new saved as file, not the previous copy. This is different to Visual Studio 6, and other sensible applications.

Deployment to a non .NET machine is another ball game!

ASPX

Accessing a web service

Back to Library