Programming with C#

This document describes the Tips and the lessons learnt from C# development. C# is a simplified form of C++, which has a Java like syntax.  It is very easy to use compared to C++.  All the memory management is taken care by .NET

1.1   Programming

1.1.1   Exception Handling

Exception are handled by using the try/catch/finally block. If the exceptions are not caught, they are just thrown out of the method

try

{

OleDbCommand insertCMD = new OleDbCommand(String.Empty, Connect());

while( enumerator.MoveNext() )

{

diskData = (DiskVO)enumerator.Current;

insertStr = baseInsStr +

” Values(‘” +

diskData.GetName() + “‘, ” +

diskData.GetSize() + “, ” +

diskData.GetFreeSpace() + “, ” +

clientID + “)”;

insertCMD.CommandText = insertStr;

insertCMD.ExecuteNonQuery();

}

}

catch(Exception e)

{

//Log the error

}

finally

{

//close the connection

Close();

}

The finally block will get executed during both exception and non-exception conditions

1.1.2   Vitrual, new and override

Virtual methods are binded during run-time.  The method which is declared as virtual can be overridden in the sub class by using the keyword override.  The new keyword is used to hide a super class’s method which is not declared as virtual.

1.2   GUI Programming

1.2.1   Different between Show and ShowDialog

The Form.Show will not block the current thread, while the Form.ShowDialog will block the current thread and wait for the user response.

1.2.2   Cancel Closing Event

To cancel a closing event (which could be a Alt+F4 keystrok or clicking the X button on the form) use the following code

privatevoid ClickClosing(object sender, System.ComponentModel.CancelEventArgs e)

ifthisvariable) )

{

e.Cancel = true;

this.Hide();

}

1.3   Process Execution

1.3.1   Ensure Singleton Process

To ensure only one instance of an executable is running, use the following piece of code.

public static bool EnsureSingleton(String execAssembly)

{

Process current = Process.GetCurrentProcess();

Process[] processes = Process.GetProcessesByName (current.ProcessName);

bool found = false;

if(execAssembly !=  null && !execAssembly.Equals(String.Empty)) )

{

//Loop through the running processes in with the same name ;

foreach(Process process in processes)

{

//Ignore the current process

if(process.Id != current.Id)

{

execAssembly = execAssembly.Replace(“/”, “\\”);

//Make sure that the process is running from

//the exe file.

if(execAssembly !=  (execAssembly.Equals(current.MainModule.FileName)) 

{

found = true ;

break ;

}

}

}

}

return !found;

}

1.3.2   Execute a command

To execute a command in a command prompt, use the following code

//cmdStr – the command to execute

System.Diagnostics.Process.Start(“cmd”, “/c \”” + cmdStr + “\””);

The following is the code snippet for shutting down a machine

ProcessStartInfoVO proc = new ProcessStartInfoVO();

proc.FileName = “Shutdown.exe”;

proc.Arguments = “-s -c \”Shutting down your computer\” “;

To restart the computer use this option

proc.Arguments = “-r”;

1.4   Threading

1.4.1   Threading and Windows Forms

Windows Forms uses the single-threaded apartment (STA) model because Windows Forms is based on native Win32 windows that are inherently apartment-threaded. The STA model implies that a window can be created on any thread, but it cannot switch threads once created, and all function calls to it must occur on its creation thread.

1.4.2   Lock statement

Lock statements are used for creating a mutex. The lock statement will allow only one thread to execute the block of code; all other threads need to wait.

//critical section

//where dataIndices is a hashmap

lock(dataIndices)

{

UpdateDataIndices();

}

1.5   Configuration

1.5.1   App.config

The App.config is the application configuration file in XML format.  The name value pairs of the properties used within the application can be stored here

<? xml version=”1.0″ encoding=”utf-8″ ?>

<configuration >

<appSettings >

< add key=”connectionURL”

value = “Provider=Microsoft.Jet.OLEDB.4.0;Data source =  xxx.mdb”/>

< add key = “ipAddress” value = “127.0.0.1” /<

/<appSettings >

/<configuration >

The App.config gets compiled into <executable name >.exe.config and this is what
will be used during run-time

2.5.2  AssemblyInfo.cs

The AssemblyInfo.cs contains all the product details

[assembly: AssemblyTitle(“Project Title”)]

[assembly: AssemblyDescription(“Project Description”)]

[assembly: AssemblyConfiguration(“”)]

[assembly: AssemblyCompany(“Name of the company”)]

[assembly: AssemblyProduct(“Product Name”)]

[assembly: AssemblyCopyright(“Copyright @2004”)]

[assembly: AssemblyTrademark(“”)]

[assembly: AssemblyCulture(“”)]

To assembly information can be obtained from the Application Class

productLabel.Text = Application.ProductName;

versionValLabel.Text = Application.ProductVersion;

1.6   Miscellaneous

1.6.1   Beep Sound

To Produce a Beep Sound, declare the following.

public enum MessageBeepType

{

Default = -1,

Ok = 0x00000000,

Error = 0x00000010,

Question = 0x00000020,

Warning = 0x00000030,

Question = 0x00000020,

}

[DllImport(“user32.dll”, SetLastError=true)]

public static extern bool MessageBeep(MessageBeepType type);

Then make the method call to get the beep sound

//play the alert sound

MessageBeep(MessageBeepType.Warning);

1.6.2   SQL Tuning

There was a situation where we had to display one record on the front end, which required to join 9 tables.  The sql query resulted in about 17000 records, which needs to be parsed and loaded into the object graph, which will later be displayed as one record in the front end. Because of the multiple joins, it was very slow.  To resolve this we broke the query into 4 different queries, thereby the total number of records retrieved is reduced.

The primary key returned from the first query is stored in a hashmap, which will later be used to match the records retruned by the other 3 queries.

1.6.3   Sorting ArrayList

Inorder to sort an arraylist, the objects within the arraylist should implement CompatrTo method.

override public int CompareTo(Object otherObj)

{

int ret = 1;

SWValueObject otherVO = (SWValueObject)otherObj;

String displayName = GetDisplayName();

String otherDispName = null;

if(otherVO != null)

{

otherDispName = otherVO.GetDisplayName();

}

if(displayName != null)

{

ret = displayName.CompareTo(otherDispName);

}

else if(displayName != null)

{

ret = otherDispName.CompareTo(displayName);

}

else

{

ret = 0;

}

}

1.6.4   Regular Expression and Match

Regular expressions and Match can be used for searching patterns in a string

String searchCriteria = searchStr.Replace(“.”, “\\.”);

// Create a new Regex object.

Regex regex = new Regex(searchCriteria);

Match match = regex.Match(ipAddress);

if(match.Success)

{

//operation

}

1.6.5   Timer

To provide a Timer functionality for the application, we can use the Environment.TickCount property.

Int startTick = Environment.TickCount;

public void UpdateTimer()

{

int current = 0;

while( (current = (Environment.TickCount – startTick)/1000) <= SHOW_TIME)

{

timerLabel.Text = (SHOW_TIME – current).ToString();

Thread.Sleep(1000);

}

}

1.6.6   Math.Ceiling vs Math.Rounding

Math.Rounding will round a real number to the next whole number if the decimal part is greater or equal to 0.5 or just the whole number if the decimal part is less than 0.5.

double roundSize =System.Math.Ceiling(physicalSize/1024.0);

Math.ceiling gives the next whole number for any real number with a decimal part greater than 0

double ram = Math.Round(physicalSize/1024.0 + 0.5);

2   WMI

WMI (Windows Management Instrumentation) can be used to query hardware details of a computer.  The following code snippet describes how to get the memory data using WMI classes.

ManagementObjectSearcher moSearcher = new ManagementObjectSearcher();

ObjectQuery memObjectQuery = new ObjectQuery(

“Select TotalVirtualMemorySize, “

+ “TotalVisibleMemorySize From Win32_OperatingSystem”);

moSearcher.Query = memObjectQuery;

ManagementObjectCollection queryCollection = moSearcher.Get();

//loop throught each object to get drive information

foreach ( ManagementObject mo in queryCollection)

{

MemoryVO memData = new MemoryVO();

System.Console.WriteLine(

System.Convert.ToInt64(mo[“TotalVisibleMemorySize”]));

System.Console.WriteLine(

System.Convert.ToInt64(mo[“TotalVirtualMemorySize”]));

}

2.1   Performance Counter

Performance Counters can be used to get the system’s performance information such as CPU performance, memory and disk usage etc.   Following is the code snippet to get CPU usage information.

PerformanceCounter cpuCounter =new PerformanceCounter();

cpuCounter.CategoryName=”Processor”;

cpuCounter.CounterName=”% Processor Time”;

cpuCounter.InstanceName=”_Total”;

System.Console.WriteLine(“CPU Usage: ” + cpuCounter.NextValue());

The following code snippet is for getting the memory usage of a computer.

PerformanceCounter memCounter = new PerformanceCounter();

memCounter.CategoryName=”Memory”;

memCounter.CounterName=”Commit Limit”;

totalMemory = System.Convert.ToInt64(memCounter.NextValue());

memCounter.CounterName=”Committed Bytes”;

usedMemory = System.Convert.ToInt64(memCounter.NextValue());

memoryUsage = (float)Math.Round(

(usedMemory) / (double)totalMemory*100.0, 2);

The counter name and the instance name can be obtained starting the Management Console through Control Panel -> Administrative Tools -> performance (in Windows 2000).  In the Management Console, bring up the ‘Add Counter’ dialog box by clicking the ‘+’ icon. The ‘Performance Object’ drop down is the category name, the counter names and its instance names are listed separately in the list boxes.

2.2   Software List

List of software installed on the computer can be obtained from by the registry, following is the code snippet.

string uninstallKey =  @”SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall”;

using(RegistryKey regkey =

Registry.LocalMachine.OpenSubKey(uninstallKey))

{

foreach(string swKeyName in regkey.GetSubKeyNames())

{

using(RegistryKey sk = regkey.OpenSubKey(swKeyName))

{

if(!swKeyName.StartsWith(“{“))

{

System.Console.WriteLine(swKeyName);

}

}

}

}