SPS Home    >   Dgreath    >   C# Statement Keywords

C# Statement Keywords

Presented here are examples of the various C# statements that demostrate some of the ways these can be deployed to solve common programming problems.  Basic statements provide branching (if, if-else, switch), and iteration (for, foreach, do-while, and while) and exception handling (try-catch, try-finally, try-catch-finally). Often these are used in combination with others (break, continue, goto,  return, and throw) to handle more complex situations.


assignment - instantiation

The statement on the Right Hand Side (RHS) is evaluated and the results placed in the Left Hand Side (LHS) variable. The type of the RHS results must be the same as the LHS, either directly or by either a cast or conversion.

The general form looks like this:
LHS = RHS

A cast looks like this:
String myString = (string)someVar;

A conversion looks like this:
String myString = Convert.ToString(someVar);
—or—
String myString = SomeVar.ToString();

Instantiation of a class or struct looks like this:
var myInstance = new Instance();

break

The break statement is used to pass program control out of a loop.

for(int i = 1; i <= 10; i++)
{
   //Some executable code
   if(i%5 = 0)
   {
      break;
   }
}

In this fragment, execution will loop and process iterations 1 through 5, then it will stop execution and progress to the next statement.

checked

The checked statement is used to enable arithmetic overflow checking on an expression.

int x = -1;
foreach(var item in items)
{
   checked { x++; };
   //Do something that uses x:
}

In this case the foreach loop will run up to 2,147,483,647 times and on the next iteration will throw an OverflowException.

continue

The continue statement is used to pass program control to the next iteration of a loop.

for(int i = 1; i <= 10; i++)
{
   //Some executable code
   if(i%2 = 0)
   {
      continue;
   }
}

In this fragment, execution will loop and process iterations 1 through 10 but will skip 3, 5, 7, and 9.

default

The default keyword returns the default value of a type. For reference types, this is null and for value types is 0.

default(Int32); //returns 0
default(Boolean); //returns false
default(String); //returns null

do-while

The do-while functions similarly to the various while formations except that the executable code is guaranteed to execute at least once.Other variations of the while loop include break, continue, goto, return and throw.

do
{
   //code to execute;
} while (boolean expression)

for

Basic loop iteration is done with the for statement. This is the approach used where the number of iterations is known, either explictly or implicitly by reference and features a counter. For loops can be modified by continue, break, or goto statements in the event loop behavior encounters an exceptional case during processing.

for(int i=1; i <= 10; i++)
{
   //executable code here (can reference i)
}

Here, the executable code will execute ten times, starting at one and ending at ten. To count down instead, the for statement would be for(int i = 10; i >= 1; i--).


for(int i=1; i <= 10; i++)
{
   if(some condition)
   {
      continue;
   }
   //executable code here (can reference i)
}

Here, the executable code will execute ten times, starting at one and ending at ten.. When the if statement precedes the executable code, the following code will not execute on that iteration if it is true. Alternatively, if the if statement follows the executable code, it will execute, but the next iteration will be skipped.


for(int i=1; i <= 10; i++)
{
   //executable code here (can reference i)
   if(some condition)
   {
      break;
   }
}

Here, the executable code will execute ten times, starting at one and ending at ten.. When the if statement follows the executable code, the following code will execute on that iteration, then further processing will cease if it is true. Alternatively, if the if statement preceedes the executable code, it will cease looping without executing the code. Program execution will continue with the next statement following. Note that if the for loop in nested inside of another loop, executing a break will terminate the inner loop only and return control to the next outer loop.


for(int i=1; i <= 10; i++)
{
   //executable code here (can reference i)
   if(some condition)
   {
      goto end;
   }
}

end:
//continue execution here

Here, the executable code will execute ten times, starting at one and ending at ten. When the if statement follows the executable code, the following code will execute on that iteration, then further processing will cease if it is true . Alternatively, if the if statement preceedes the executable code, it will cease looping without executing the code when true. Program execution will continue at the indicated label.  Note that if the for loop in nested inside of another loop, executing a goto will terminate processing of the inner loop and all containing loops.


for(int i=1; i <= 10; i++)
{
   if(some condition {which can reference i})
   {
      throw MyException():
   }
   //executable code here (can reference i)
}

Here, the executable code will attempt to execute ten times, starting at one and ending at ten. When the if statement evaluates to true, an exception will be thrown and processing stops. If false, the following code will execute on that iteration. Normally this code block would be wrapped in a try-catch block which will control subsequent processing.

foreach-in

The foreach statement is used to iterate through data collections that implement IEnumerable such as a datatable.

DataTable dt0 = fetchSomeData();
DataTable dt1 = dto.Clone;

foreach(DataRow dr0 in dt.Rows())
{
   DataRow dr1 = dt1.NewRow();
   dr1["Field0"] = (string)dr0["Field0"];
   dr1["Field1"] = (string)dr0["Field1"];
   dr1["Field2"] = (string)dr0["Field2"];
   dt1.Rows.Add(dr0);
}

This example copies three fields in every row from one table to another cloned from it.


DataTable dt0 = fetchSomeData();
DataTable dt1 = dto.Clone;

foreach(DataRow dr0 in dt.Rows())
{

   if(dr0["Field0"] == null)
   {
      continue;
   }

   DataRow dr1 = dt1.NewRow();
   dr1["Field0"] = (string)dr0["Field0"];
   dr1["Field1"] = (string)dr0["Field1"];
   dr1["Field2"] = (string)dr0["Field2"[;
   dt1.Rows.Add(dr0);
}

This example copies three fields in rows from one table to another cloned from it unless field one is null where that row is skipped.


DataTable dt0 = fetchSomeData();
DataTable dt1 = dto.Clone;

foreach(DataRow dr0 in dt.Rows())
{
   DataRow dr1 = dt1.NewRow();
   dr1["Field0"] = (string)dr0["Field0"];
   dr1["Field1"] = (string)dr0["Field1"];
   dr1["Field2"] = (string)dr0["Field2"[;
   dt1.Rows.Add(dr0);
   if((string)dr0["Field0"] == "OUT OF STOCK")
   {
      break;
   }

}

This example copiess three fields in rows from one table to another cloned from it until the first occurrance of "OUT OF STOCK" occurs. Processing ends at that point. If the if statement precedes the data copying, the "OUT OF STOCK" row would not be copied. If it follows the data copying, it will be the last row copied.

goto label

The goto statement is used to pass program control out of a loop and to a specified label. Conceptually, gotos are sometimes used to jump 'forward' to a label while 'breaks' are used to either jump backward or exit a loop.  Gotos are also useful for exiting out of the inner loop of nested loops without having to back out of each containing loop. The case and default statements in a switch statement are technically labels and can be the target of a goto.

for(int i = 1; i <= 10; i++)
{
   //Some executable code
   if(i%5 = 0)
   {
      goto labelA;
   }
}

labelA:
//do something...

In this fragment, execution will loop and process iterations 1 through 5, then it will stop execution and jump to the specified label.

if

if(boolean condition)
{
   //code to be executed if condition is true
}

if-else

if(boolean condition)
{
   //code to be executed if condition is true
}
else
{
   //code to be executed if condition is false
}

lock

When a static method can be invoked from muliple threads and the possiblity exists of method corruption, the method can be locked to prevent this from happening.Not all static methods require this treatment and applying it to such methods when not needed can cause performance issues. Cases when locking should not be used are where all values to be operated upon are passed in as arguments and the final result returned as in the case of a "pure" function.

public class Demo
{
   private static Object synchLock = new Object();

   public static void MyStaticMethod()
   {
      lock(synchLock)
      {
         //implementation code goes here
      }
   }
}

return

The return statement is used to pass program control from a method back to whatever called it.

if(a > b)
{
   return "something";
}

The return statement is required for all non-void methods.

switch-case-default

Switch provides an alternative to the boolean limitations of an if-else construct, however it is more restrictive than nested if-else constructs. A value is passed in and is tested by sequential case statements until a case condition is satisfied.  Note that each case statement must be terminated with a jump statement (break, goto, return, or throw). Default is optional but should be included if there is any possiblity that the switch value is other than a defined case.

switch(value)
{
   case "a":
      //code to be executed for case A
      break;
   case "b":
      //code to be executed for case B
      break;
   case "c":
      //code to be executed for case C
      break;
   default:
      //code to be executed if not A, B, or C
      break;
}

//Execution continues here

In this configuration, the cases are evaluated and the selected code is executed. Upon completion, program execution moves on to the next statement following the switch block.


public void SomeMethod()
{
   switch(value)
   {
      case "a":
         //code to be executed for case A
         return;
      case "b":
         //code to be executed for case B
         return;
      case "c":
         //code to be executed for case C
         return;
      default:
         //code to be executed if not A, B, or C
         return;
   }
}

In this configuration, the cases are evaluated and the selected code is executed. Upon completion, program execution returns to the calling method once the code is processed.


public void SomeMethod()
{
   switch(value)
   {
      case "a":
         goto labelA;
      case "b":
         goto labelB;
      case "c":
         goto labelC;
      default:
         return;
   }

   labelA:
   //code to handle case A
   return;

   labelB:
   //code to handle case B
   return;

   labelC:
   //code to handle case C
   return;
}

In this configuration, the cases are evaluated and execution jumps to the referenced label. Upon completion, program execution returns to the calling method once that code is processed.  Goto jumps can also go to case and default statements within the switch since both are labels.


public void SomeMethod()
{
   switch(value)
   {
      case "a":
         throw RedException(message);
      case "b":
         throw BlueException(message);
      case "c":
         throw GreenException(message);
   }
}

In this configuration, the cases are evaluated and one of three exceptions is thrown.


public void SomeMethod()
{
   switch(value)
   {
      case "a":
         //code to be executed for case A
         return;
      case "b":
         //code to be executed for case B
         break;
      case "c":
         goto labelC;
      default:
         throw MyException(message);
   }

   labelC:
   //code to handle case C
   return;
}

In this configuration, various combinations of jumps are shown.

throw

The throw statement is used to trigger exceptions. These are commonly used in "catch" blocks but also can be used in simple "if" blocks.

if(a > b)
{
   throw new exception();
}

This is useful in the case of nested try-catch blocks to permit the "outer" catch block to handle the exception caught by the "inner" catch block. Note that eventually unhandled exceptions will bubble up and and cause the application to stop. In a properly designed application, these exceptions should be handled at the local level (Try-Catch statements) or page level (Page_Error delegate on code-behind page) or at the application level (Application_Error delegate in global.asax)

Note that throw preserves the stack trace, however, throw ex resets the stack trace first. You would use the latter method when the current method handled the lower exception and you are throwing an exception from "this" method where the child method's trace is not relevant.

try-catch

The try-catch statement is used to obtain and use resources and handle exceptions. It does not automatically release resources when done.

try()
{
   //code to be executed goes here
}
catch(Exception ex)
{
   //error handling code goes here
}

In cases where the try-catch could receive multiple exceptions, the block can be configured with as many catch blocks as necessary. In the following example, both 'blue' and 'red' exceptions are handled:

try()
{
   //code to be executed goes here
}
catch(BlueException ex)
{
   //error handling code for 'blue' exceptions
}
catch(RedException ex)
{
   //error handling code for 'red' exceptions
}

Note that catch block are processed in the order presented and the first exception caught ends processing (subsequent blocks are not evaluated). Alternatively, if all exceptions must be handled, try-catch blocks can be nested.

try-finally

The try-finally statement is used to obtain and use resources then release resources when done. Exceptions, if any, are ignored.  This is functionally equivalent to the using statement.

//declaration of objects to be disposed
try()
{
   //code to be executed goes here
}
finally()
{
   //disposal code goes here
}

The disposal code is always executed. Note that the objects to be disposed must be declared before the "try" block.

try-catch-finally

The try-catch-finally statement is used to obtain and use resources, handle exceptions, and release resources when done.

//declaration of objects to be disposed
try()
{
   //code to be executed goes here
}
catch(exception ex)
{
   //error handling code goes here
}
finally()
{
   //disposal code goes here
}

The disposal code is always executed. Note that the objects to be disposed must be declared before the 'try' block.

Multiple catch blocks can be implented as well. They will be processed in order and the first one to catch the exception will end catch processing (remaining catch blocks will not be evaluated).

unchecked

The unchecked statement is used to disable arithmetic overflow checking on an expression.

int x = -1;
foreach(var item in items)
{
   unchecked { x++; };
   //Do something that uses x:
}

In this case the foreach loop will run up to 2,147,483,647 times and on the next iteration will reset x to zero and continue executing.

using

Types that implement IDisposable should be called with the using statement to ensure that IDisposable is called under all situations. This is functionally equivalent to the try-finally statement.

using(Font f1 = new Font("Arial", 10.0f);
{
   //Implementation code goes here
}

while

The while statement will loop continuously as long as the boolean expression evaluates to true. It does not have a counter, use a "for" statement when that's needed. Since the boolean expression evaluates prior to every iteration of the loop, it will not execute it's code block when false and program execution will pass to the next statement. Other variations of the while loop include break, continue, goto, return and throw. See the for loop (above) for examples of how and when these are used.

while(boolean expression)
{
   //code to execute;
}

yield

The yield  keyword indicates that the method, operator, or get accessor is actually an iterator for an IEnumerable or IEnumerator. Typically these are used with foreach loops and causes each loop of the iteration to call the iterator method, return the value of the expression, and retain the current location in the list  In the next iteration, processing resumes at that point. The code below shows how this works:


int i = -1;
foreach(var item in items)
{
   i++
if(predicate(item, i)) yield return item;
}

For a lamda expression of t =>t.key == "somevalue", the predicate would look like
private typeof(t) Func(object t, int i){item.key == "somevalue"}.
The value of i is how yield keeps track of where it is in the enumeration.