A year since playing with C# I've now deployed a real application! What difficulties did I have?
Here are some fragments from my "solution":
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.
}
No examples - but obvious.
private void CalcSlotTime(DateTime dt, int slot, out DateTime slot_time)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!)
Note the scoping of int a. It works correctly, unlike Microsoft's C++!
for (int a = 0; a < linear_array.Length; a++)Objects, such as int, know how to represent themselves as strings. Very kind of them.
int num = 42;
string sz;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)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.
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_structI can use this wondrous structure I've proudly created...
public Form1()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...
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!
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.
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.