Basic Programming Elements of C#

After you have an understanding of the structure of an object-oriented program, the rest is pretty much just filling in the blanks. Now you can quickly go through each of the basic elements of a C# program.

abstract

I have discussed a little bit about an abstract class. You can use the abstract modifier to declare an abstract method or property. An abstract class has the following properties:

  • An abstract class cannot be instantiated.

  • A non-abstract class that is derived from an abstract class must implement all of the abstract methods and properties.

  • An abstract class must provide implementations for all of the methods of an inherited interface.

  • An abstract class can declare its “implementation” of an interface method to be abstract, thus forwarding the responsibility of implementation to the class that derives from it.

Listing A.31 shows the implementation of a basic abstract class.

Listing A.31. Using abstract
using System;

namespace Testing
{
    // Abstract class
    abstract class Point
    {
        protected int x = 0;
        protected int y = 0;
        // Abstract methods
        public abstract void Increment();
        public abstract void Decrement();

        // Abstract properties
        public abstract int X
        {
            get;
        }

        public abstract int Y
        {
            get;
        }
    }

    class NewPoint: Point
    {
        public override void Increment()
        {
            x++;
            y++;
        }
        public override void Decrement()
        {
            x--;
            y--;
        }

        public override int X
        {
            get
            {
                return x;
            }
        }

        public override int Y
        {
            get
            {
                return y;
            }
        }
    }
    class AbstractMain
    {
        public static void Main()
        {
            NewPoint p = new NewPoint();
            p.Increment();
            p.Increment();
            p.Decrement();
            Console.WriteLine("x = {0} , y = {1} ", p.X, p.Y);
        }
    }
}
. . .
x = 1, y = 1
I am in A
I am in B
I am in C

It should be noted that an abstract method or property is implicitly virtual, and abstract methods and properties can only be defined in an abstract class. The code in Listing A.31 obeys these rules.

Listing A.32 shows a short example of using abstract in conjunction with an interface.

Listing A.32. Using abstract with an interface
interface IFunctions
{
    void A();
    void B();
    void C();
}
abstract class Function : IFunctions
{
    public void A()
    {
        Console.WriteLine("I am in A");
    }
    public abstract void B();
    public abstract void C();
}
. . .
class NewFunction : Function
{
    public override void B()
    {
        Console.WriteLine("I am in B");
    }
    public override void C()
    {
        Console.WriteLine("I am in C");
    }
}
. . .
NewFunction f = new NewFunction();
IFunctions i = (IFunctions)f;
i.A();
i.B();
i.C();

Notice that the abstract class either implemented the interface method (as in method A) or forwarded the responsibility on to the deriving class by making the interface method abstract (as in methods B and C).

as

This operator returns a null if the class is not derived from the specific class or interface. If it has in its hierarchy the class or interface, then a reference to the class or interface is returned. An example of using the as operator is shown in Listing A.33.

Listing A.33. Using as
class C
{
}
class B : C
{
}
class A : B
{
}

class AsMain
{
    public static void Main()
    {
        A a = new A();
        B b = new B();
        C c = new C();
        try
        {
            B bcc = (B)c;
        }
        catch(Exception e)
        {
            Console.WriteLine(e);
        }
        B bc = c as B;
        if(bc == null)
            Console.WriteLine("C is not a B");
        B ba = a as B;
        if(ba == null)
            Console.WriteLine("A is not a B");
    }
}

The code of Listing A.33 outputs the following:

System.InvalidCastException: Specified cast is not valid.
   at Testing.AbstractMain.Main()
C is not a B

At first, an exception is thrown because C is not derived from B and cannot be cast to a B object. By using as, a null is returned to avoid having the overhead of an exception.

base

This operator is used to access members of a base class from a derived class. It can only be called from within properties or methods in a derived class. It cannot be called from a static method. Typically, it would be called from a constructor:

public Foo(string s) : base(s)

This would call the base constructor for the object with an argument of a string. This operator can also be used from a method or property:

base.Bar();

This would call the Bar method in the base class. Typically, this would be used to disambiguate a call to a base class method that has the same signature as the calling method.

break

This statement terminates the closest enclosing loop or conditional statement. Look at Listing A.34.

Listing A.34. Using break
public static void Main()
{
    string input;
    Console.WriteLine("Starting loop.");
    while(true)
    {
        Console.Write("Input . . .");
        input = Console.ReadLine();
        if(input[0] == 'B')
            break;
    }
}

This program will continue to run until the user enters a string starting with 'B', at which point the program terminates.

Break is also used to exit a switch block.

A switch statement is an alternative to if when it is possible for an object to have more than two different values.

Listing A.50 shows the basic uses of a switch statement.

case

A case statement is always included as part of a switch statement. A switch statement is an alternative to if when it is possible for an object to have more than two different values. The case statement delimits the sections of code that should be executed if the match condition specified by the case statement occurs.

catch

See Chapter 15 “Using Managed Exceptions to Effectively Handle Errors,” for examples of using try/catch/finally with exceptions.

checked

This operator forces an exception to be thrown if an integer overflow occurs. The opposite unchecked makes sure that the output is not checked for overflow condition. Listing A.35 shows these two operators in action.

Listing A.35. Using checked and unchecked
class CheckedMain
{
    static short x = Int16.MaxValue;
    static short y = Int16.MaxValue;
    static int AddShort()
    {
        int ret = 0;
        try
        {
            ret = (short)(x + y);
        }
        catch(Exception e)
        {
            Console.WriteLine(e);
        }
        return ret;
    }
    static int AddCheckedShort()
    {
        int ret = 0;
        try
        {
            ret = checked((short)(x + y));
        }
        catch(Exception e)
        {
            Console.WriteLine("Checked:");
            Console.WriteLine(e);
        }
        return ret;
    }
    static int AddUncheckedShort()
    {
        int ret = 0;
        try
        {
            ret = unchecked((short)(x + y));
        }
        catch(Exception e)
        {
            Console.WriteLine("Unchecked:");
            Console.WriteLine(e);
        }
        return ret;
    }
    public static void Main()
    {
        Console.WriteLine("AddShort returns: {0} ",
                               AddShort());
        Console.WriteLine("AddCheckedShort returns: {0} ",
                               AddCheckedShort());
        Console.WriteLine("AddUncheckedShort returns: {0} ",
                               AddUncheckedShort());
    }
}

The output for Listing A.35 is as follows:

AddShort returns: -2
Checked:
System.OverflowException: Arithmetic operation resulted in an overflow.
   at Testing.CheckedMain.AddCheckedShort()
AddCheckedShort returns: 0
AddUncheckedShort returns: -2

const

The modifier const specifies that the field or local variable cannot be modified. As a field in a class, it might look like this:

public const int c1 = 5;

As a local variable, it might look like this:

const int c1 = 5;

If you attempt to modify a const value, the compiler generates an error like this:

error CS0131: The left-hand side of an assignment must be a
        variable, property or indexer

continue

The continue directive forces execution to continue at the bottom of the nearest enclosing loop. Listing A.36 shows a possible usage of continue.

Listing A.36. Using continue
public static void Main()
{
    string input;
    bool stop = false;
    Console.WriteLine("Starting loop.");
    while(!stop)
    {
        Console.Write("Input . . .");
        input = Console.ReadLine();
        if(input[0] != 'B')
        {
            continue;
        }
        stop = true;
    }
}

The line stop = true; is skipped until the user enters a string beginning with 'B'.

default

A default statement is always included as part of a switch statement. A switch statement is an alternative to if when it is possible for an object to have more than two different values. The default statement matches all cases that are not specifically specified by case statements.

delegate

A delegate wraps the signature of a function or method into a class. delegates have been likened to function pointers in C or C++. After a delegate is defined, it can be used to reference a method or function without having to know at compile time which function or method will be invoked. The key feature of a delegate is that it is a type-safe, and secure way to reference a function or method. delegates are covered in detail in Chapter 14, “Delegates and Events.”

do

The keyword begins a do/while block that continually executes until the expression in while evaluates to false. Note that unlike while, this statement always executes the enclosing block at least once. Listing A.37 shows an example.

Listing A.37. Using do
public static void Main()
{
    string input;
    bool stop = false;
    Console.WriteLine("Starting loop.");
    do
    {
        Console.Write("Input . . .");
        input = Console.ReadLine();
        if(input[0] == 'B')
            stop = true;
    }
    while(!stop);
}

else

If is a control statement that executes a statement block if the expression supplied as an argument to the if statement evaluates to true. The if statement has an optional else clause that is executed if the expression evaluates to false.

if(x > 0)
    Console.WriteLine("X > 0");
else
    Console.WriteLine("X <= 0");

event

An event wraps the functionality of a delegate into yet another class that only exposes two operators, the += operator for adding a delegate to an event list, and the -= operator for removing a delegate from an event list. Declaring an event requires two arguments. The first is the delegate signature for the method or function that will be added into this event, and the second is the name of the variable that holds the event.

Events are covered in detail in Chapter 14.

explicit

This modifier forces the user to do an explicit cast conversion. This is the opposite of implicit, which allows for a silent, automatic conversion. Listing A.38 shows a simple application using implicit and explicit.

Listing A.38. Using explicit and implicit
struct Complex
{
    double real;
    double imag;
    public Complex(double real, double imag)
    {
        this.real = real;
        this.imag = imag;
    }
    public override string ToString()
    {
        return (string.Format("({0} , {1} i)", real, imag));
    }
    public static explicit operator Complex(double r)
    {
        return new Complex(r, 0);
    }
    public static implicit operator Complex(double [] n)
    {
        if(n.Length != 2)
            throw new ArgumentException();
        return new Complex(n[0], n[1]);
    }
}

class ExplicitMain
{
    static void Main(string[] args)
    {
        Complex cn = new Complex(1,0);
        Console.WriteLine("{0} ", cn);
        cn = (Complex)2;
        Console.WriteLine("{0} ", cn);
        double [] da = new double [] {3,0} ;
        cn = da;
        Console.WriteLine("{0} ", cn);
    }
}

Notice that the conversion from double to Complex requires an explicit cast, whereas the conversion from an array of double to Complex is done implicitly. If the explicit cast is removed, then the compiler flags it as an error, indicating that no conversion can be done implicitly.

extern

Commonly used with the DllImport attribute, this modifier declares that a function is defined externally. There are many examples of using the extern directive in Chapter 7, “Leveraging Existing Code—P/Invoke.”

finally

Finally is a way of stipulating that a section of code must be executed no matter how the execution path leaves the current scope.

See Chapter 15 for examples of using try/catch/finally with exceptions.

fixed

This statement prevents the garbage collector from relocating memory. It “pins” the memory for the duration of the associated block of statements. See Listing A.28 for an example.

for

This statement sets up a loop that first executes the statements in the initialization section. It then executes the iterator section and the statement associated with the for loop as long as the expression evaluates to true. Listing A.39 shows a simple example of using for.

Listing A.39. Using for
for(int i = 0; i < 5; i++)
    Console.WriteLine("{0} ", i);

This simple section of code simply prints the numbers 0 through 4.

foreach

This construct allows you to iterate through any collection that supports the GetEnumerator method that returns an enumerator. A simple example looks like Listing A.40.

Listing A.40. Using foreach with an Array
string [] sa = new string [] { "This", "is", "a", "test" } ;
foreach(string s in sa)
{
    Console.WriteLine(s);
}

Arrays of any value support the foreach construct. In addition, the collections classes support the required enumerators to use in foreach. It is also possible to use foreach with user-defined classes. When building a user-defined class that can work with foreach, you can use two approaches. The first approach enables the user to iterate through a collection only in C#. The second approach not only allows the user to iterate through a collection with C# and foreach, but it also allows iteration using another language, such as VB. Listing A.41 shows the C#-specific approach.

Listing A.41. Using foreach with a C# Collection
// Declare the collection:
public class CSharpCollection
{
    int[] items;

    public CSharpCollection()
    {
        items = new int[5] {1, 2, 3, 4, 5} ;
    }

    public CSharpEnumerator GetEnumerator()
    {
        return new CSharpEnumerator(this);
    }

    // Declare the enumerator class:
    public class CSharpEnumerator
    {
        int nIndex;
        CSharpCollection collection;
        public CSharpEnumerator(CSharpCollection coll)
        {
            collection = coll;
            nIndex = -1;
        }

        public bool MoveNext()
        {
            nIndex++;
            return(nIndex < collection.items.GetLength(0));
        }

        public int Current
        {
            get
            {
                return(collection.items[nIndex]);
            }
        }
    }
}
. . .
CSharpCollection col = new CSharpCollection();
Console.WriteLine("Values in the C# collection are:");
foreach (int i in col)
{
    Console.WriteLine(i);
}

To allow foreach to iterate through a custom collection, you need to follow these rules:

  • You need to define the collection as part of an interface, struct, or class.

  • The class or structure needs to define a method GetEnumerator that returns an Enumerator type.

  • The Enumerator type returned by GetEnumerator needs to implement a Current property that returns an item of the correct type or a type that can be converted to the underlying type contained in the collection.

  • The Enumerator type also must implement a MoveNext method that returns a bool of false when the end of the collection has been reached.

Listing A.42 shows a generic approach to iterating through collections.

Listing A.42. Using foreach with a Generic Collection
. . .
Systems.Collections;
. . .
public class GenericCollection: IEnumerable
{
    int[] items;
    public GenericCollection()
    {
        items = new int[5] {6, 7, 8, 9, 10} ;
    }

    public GenericEnumerator GetEnumerator()
    {
        return new GenericEnumerator(this);
    }

    // Implement the GetEnumerator() method:
    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
    // Declare the enumerator and implement the IEnumerator interface:
    public class GenericEnumerator: IEnumerator
    {
        int nIndex;
        GenericCollection collection;
        public GenericEnumerator(GenericCollection coll)
        {
            collection = coll;
            nIndex = -1;
        }

        public void Reset()
        {
            nIndex = -1;
        }

        public bool MoveNext()
        {
            nIndex++;
            return(nIndex < collection.items.GetLength(0));
        }

        public int Current
        {
            get
            {
                return(collection.items[nIndex]);
            }
        }

        // The current property on the IEnumerator interface:
        object IEnumerator.Current
        {
            get
            {
                return(Current);
            }
        }
    }
}
. . .
GenericCollection gencol = new GenericCollection();
Console.WriteLine("Values in the generic collection are:");
foreach (int i in gencol)
{
    Console.WriteLine(i);
}

For the generic approach, you need to follow all of the rules that apply to the C#-specific case. In addition, you need to implement the IEnumerable interface.

goto

Transfers control to a labeled statement. Unlike its C++ predecessor, this jump has some restrictions on where it can go. For example, a C# goto cannot jump into a statement block.

See switch for how to use goto in a switch statement.

if

if is a control statement that executes a statement block if the expression supplied as an argument to the if statement evaluates to true. The if statement has an optional else clause that is executed if the expression evaluates to false.

if(x > 0)
    Console.WriteLine("X > 0");
else
    Console.WriteLine("X <= 0");

implicit

See explicit for an example of how to use explicit versus implicit.

in

See foreach.

interface

An interface is a way of describing a set of methods that have no implementation. It is the responsibility of the class or struct inheriting from an interface to implement each of the methods described as part of the interface. The methods declared as members of an interface are implicitly abstract. It is an error to explicitly declare the methods abstract. You would use an interface if you wanted to guarantee that certain methods would be implemented on a certain set of your classes. You can even check to make sure that a given instance implements a particular interface either through a direct cast and catching an exception or by using the as operator. Listing A.43 (or the associated code in interface.cs) illustrates the usages of the interface keyword.

Listing A.43. Using interface
interface ICommunicate
{
    void Speak(string s);
    void Listen(string s);
    void Read(string s);
    void Write(string s);
}
interface ITravel
{
    void Walk();
    void Car();
    void Train();
    void Plane();
}
class Activities: ICommunicate, ITravel
{
}
. . .
Activities a = new Activities();
try
{
    IComparable ic = (IComparable)a;
}
catch(Exception e)
{
    Console.WriteLine(e);
}
if(a is ICommunicate)
{
    ICommunicate ac = (ICommunicate)a;
    ac.Speak("I said that");
    ac.Listen("I am talking to you");
    ac.Read("The quick brown fox jumped over the lazy cow.");
    ac.Write("What I did on my summer vacation.");
}
if(a is ITravel)
{
    ITravel at = (ITravel)a;
    at.Walk();
    at.Car();
    at.Train();
    at.Plane();
}
Console.WriteLine("--------------------------");
ICommunicate c = a as ICommunicate;
if(c != null)
{
    c.Speak("I said that");
    c.Listen("I am talking to you");
    c.Read("The quick brown fox jumped over the lazy cow.");
    c.Write("What I did on my summer vacation.");
}
ITravel t = a as ITravel;
if(t != null)
{
    t.Walk();
    t.Car();
    t.Train();
    t.Plane();
}

internal

The internal access modifier allows access to a particular type only from files that comprise a single assembly. Other assemblies do not have access to this type. Listing A.44 shows a library created from external.cs. That library is being used with internal.cs to create a program.

Listing A.44. Building an Application from Multiple Files
(internal.cs)
// csc /r:external.dll internal.cs
using System;

namespace Testing
{
    class InternalMain
    {
        static void Main(string[] args)
        {
            InternalClass ic = new InternalClass();
        }
    }
}
(external.cs)
// csc /t:library external.cs
using System;

namespace Testing
{
    public class InternalClass
    {
        public InternalClass()
        {
            Console.WriteLine("Constructing InternalClass");
        }
    }
}

Modify Listing A.44 to use the internal modifier. Now the listing looks like Listing A.45.

Listing A.45. Building an Application from Multiple Files
 (external.cs)
// csc /t:library external.cs
using System;

namespace Testing
{
    internal class InternalClass
    {
        public InternalClass()
        {
            Console.WriteLine("Constructing InternalClass");
        }
    }
}

The compile statement from Listing A.44 of internal.cs fails with an error indicating that the class is not accessible.

is

Test for runtime type compatibility with a given object. See the previous section on interfaces for examples of using this operator.

lock

See Chapter 11, “Threading,” for examples of using the lock statement for synchronization.

namespace

The namespace keyword is used to create a scope for all of the members contained within the namespace block. When an identifier is enclosed in a namespace, it is fully qualified.

new

New constructs a new instance of an object.

operator

Three types of operators can be defined: unary, binary, and conversion. During the discussion of user-defined value types, a Complex value was defined. This value showed examples of unary and binary operators.

A conversion operator must have an additional modifier of either explicit or implicit depending on how the conversion is to take place. See explicit for examples of conversion operators.

Unary operators that can be overridden are as follows:

+ - ! ~ ++ -- true false

Binary operators that can be overridden are as follows:

+ - * / % & | ^ << >> == != > < >= <=

All operators are static methods.

out

Out is one of the method parameters that describes how arguments are passed to and from a method call. Out specifies that the called method will fill in the value for the parameter. Listing A.46 shows how to use out.

Listing A.46. Using out
public static int TestOut(out int i, out int j)
{
    i = 2;
    j = 3;
    return 1;
}
public static void Main()
{
    int a;
    int b;
    int c = TestOut(out a, out b);
    Console.WriteLine("{0}  {1}  {2} ", a, b, c);
}
. . .
2 3 1

override

An override modifier specifies that the method overrides the method with the same signature inherited from the base class. You cannot override a non-virtual or static method. See explicit for an example of the syntax used with override.

params

Params is a method parameter that specifies a variable number of arguments. Listing A.47 shows a simple example.

Listing A.47. Using params
class ParamsMain
{
    public static void TestParams(params string [] a)
    {
        foreach(string s in a)
            Console.WriteLine(s);
    }
    public static void Main()
    {
        TestParams("This", "is", "a", "test");
        string [] s = new string [] {"Monday",
                                     "Tuesday",
                                     "Wednesday",
                                     "Thursday",
                                     "Friday",
                                     "Saturday",
                                     "Sunday"} ;
        TestParams(s);
    }
}
. . .
This
is
a
test
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday

private

Private is a member access modifier. Members that are declared private are only accessible from the class or struct in which they are defined.

protected

Protected is a member access modifier. Members that are declared protected are accessible from the class in which they are defined as well as from the class that inherits the class in which they are defined.

public

Public is a member access modifier. Members that are declared public have no access restrictions.

readonly

A readonly variable can only be modified during the declaration or in the constructor of a class or struct. This differs from a const variable, which cannot be modified anywhere in the code. Listing A.48 shows how readonly can be used.

Listing A.48. Using readonly
class Readonly
{
    // const int c1 = 5;
    readonly int c1;
    public Readonly()
    {
        c1 = 6;
    }
    public int Value
    {
        get
        {
            return c1;
        }
    }
}
class ReadonlyMain
{
    public static void Main()
    {
        Readonly ro = new Readonly();
        Console.WriteLine("{0} ", ro.Value);
    }
}

If you uncomment the line where the field c1 is declared as const, a compile-time error is generated from the line where c1 is assigned in the constructor.

ref

Ref is similar to out. However, when a parameter is marked with ref, data will be transferred to the method as well as from the method, as in out.

Listing A.49 illustrates some important differences between ref and out.

Listing A.49. Using ref and out
class RefMain
{
    public static int TestRef(ref int i, ref int j)
    {
        Console.WriteLine("Entering TestRef {0}  {1} ", i, j);
        i = 5;
        j = 6;
        return 4;
    }
    public static int TestOut(out int i, out int j)
    {
        // Console.WriteLine("Entering TestOut {0}  {1} ", i, j);
        i = 2;
        j = 3;
        return 1;
    }
    public static void Main()
    {
        int a;
        int b;
        int c = TestOut(out a, out b);
        Console.WriteLine("{0}  {1}  {2} ", a, b, c);
        // int d;
        // int e;
        int d = -1;
        int e = -2;
        int f = TestRef(ref d, ref e);
        Console.WriteLine("{0}  {1}  {2} ", d, e, f);
    }
}

If you remove the comments from the Console.WriteLine in TestOut, you get a compile-time error because out parameters are unassigned on entering the method. If you remove the comments from the declarations of variables d and e and comment the declarations that contain an assignment, you also get a compile-time error because ref parameters must be initialized.

return

A return causes a return from the enclosing method or function. Optionally, a return type can be supplied as an argument to this statement.

sealed

If a class is sealed, it cannot be used as a base class to construct another class. Sealed classes offer some performance benefits, so sealing a class should be considered if it is known ahead of time that this class will not be involved in inheritance hierarchies.

stackalloc

This function is similar to _alloca in the C runtime library. It allocates a block of memory on the stack. This function must be called in an unsafe context because it returns a pointer type. The memory allocated is not subject to garbage collection, so it is not necessary to use fixed to pin the memory. Listing A.50 shows how this function is used.

Listing A.50. Using stackalloc
class StackallocMain
{
    static unsafe void FillBuffer(out int[] buffer)
    {
        buffer = new int [10];
        int count = buffer.Length;
        int *p = stackalloc int[count];
        int *t = p;
        for(int i = 0; i < count; i++)
            *t++ = i;
        t = p;
        for(int i = 0; i < count; i++)
            buffer[i] = *t++;
    }
    static void Main(string[] args)
    {
        int [] buffer;
        FillBuffer(out buffer);
        foreach(int i in buffer)
            Console.WriteLine("{0} ", i);
    }
}

This sample simply allocates some memory, initializes the contents to an increasing integer, and copies that memory to an output buffer. Of course, the main purpose of this sample is to show the usage of stackalloc.

static

This keyword specifies that a member belongs to the type rather than to an instance of the type.

switch

A switch statement is an alternative to if when it is possible for an object to have more than two different values.

Listing A.51 shows the basic uses of a switch statement.

Listing A.51. Using switch
enum Animals
{
    Cat,
    Worm,
    Mammal
}
class SwitchMain
{
static void AnimalOperations(Animals animal)
{
    switch(animal)
    {
        case Animals.Cat:
            Console.WriteLine("This is a Cat");
            goto case Animals.Mammal;
        case Animals.Worm:
            Console.WriteLine("Worm");
            break;
        case Animals.Mammal:
            Console.WriteLine("This is a mammal.");
            goto default;
        default:
            Console.WriteLine("This is also a vertebrate.");
            break;
    }
}
static void Main(string[] args)
{
    AnimalOperations(Animals.Cat);
    AnimalOperations(Animals.Worm);
    AnimalOperations(Animals.Mammal);
}

Goto statements are almost as bad in C# code as they were in C++ or C code, so it's best to avoid them. As you can see from the previous example, it is not trivial to figure out just what will be printed. Use goto only when necessary. It is used here just to be complete in the description of the syntax of a switch statement.

this

This is a reference to the enclosing object instance.

throw

See Chapter 15 for examples of using throw with exceptions.

try

See Chapter 15 for examples of using try/catch/finally with exceptions.

typeof

This operator is used to obtain a System.Type object for a given type. Listing A.52 shows how to use this operator.

Listing A.52. Using typeof
class TypeofMain
{
    public static void Main()
    {
        Type t = typeof(System.String);
        Console.WriteLine("Assembly: {0} ", t.Assembly);
        Console.WriteLine("Assembly Name: {0} ", t.AssemblyQualifiedName);
    }
}
						

unchecked

The unchecked operator makes sure that the output is not checked for overflow condition. Listing A.35 shows an example of using both checked and unchecked operators in action.

unsafe

This keyword marks a method as potentially not type safe. In an unsafe method, type safety checks are not performed. An unsafe method does not initialize the local variable automatically. Marking a method as unsafe enables a programmer to isolate unsafe code from safe code. Listing A.29 and Figure A.3 provide some examples of using the unsafe operator.

using

using has two different uses. One is to specify a namespace alias. The other is to define a scope at the end of which an object will be destroyed.

Listing A.53 shows how you can define a different alias for a namespace with using.

Listing A.53. Using the using Directive
using MySystem = System;

namespace Testing
{
    using MyCompanyAlias = MyCompany.OutputFunctions;
    namespace MyCompany
    {
        namespace OutputFunctions
        {
            class OutputToConsole
            {
                public static void Line(string s)
                {
                    MySystem.Console.WriteLine("Hello!");
                }
            }
        }
    }

    class UsingMain
    {
        public static void Main()
        {
            MyCompanyAlias.OutputToConsole.Line("Hello!");
        }
    }
}

The common usage is to just have “using System;”, which defines a blank namespace to be an alias to System, essentially prohibiting you from specifying the System namespace. Here, an alias is specified for System to be MySystem. Similarly, an alias has been defined to save some typing for MyCompany.OutputFunctions.

The other usage of using is to define a scope for an object lifetime. Many samples in Chapter 10, “Memory/Resource Management,” show resource allocation. The sample in Listing A.54 merely shows the syntax.

Listing A.54. Using the using Statement
class ResourceAllocation : IDisposable
{
    public ResourceAllocation()
    {
        Console.WriteLine("I am allocating a very expensive resource.");
    }
    public void Dispose()
    {
        Console.WriteLine("The very expensive resource is being reclaimed.");
    }
}
class DisposeMain
{
    public static void Main()
    {
        ResourceAllocation r = new ResourceAllocation();
        using(r)
        {
            Console.WriteLine("I am using the resource.");
        }
    }
}

virtual

A virtual modifier on a method indicates that this method is a candidate to be overridden by a class that inherits from the class that is defining the method. In Listing A.28, the abstract keyword implicitly defines a method as virtual. You can replace just the definition of the Shape class with Listing A.55.

Listing A.55. Using the virtual Modifier
class Shape
{
    public virtual void Draw()
    {
        Console.WriteLine("Drawing a Shape");
    }
}

The original program compiles and runs just as before. In real life, it does not make sense to define a method to draw a Shape because a Shape is an abstract concept and should be abstract. (It could even better be an interface.) However, this sample shows the usage and syntax of the virtual modifier.

volatile

A volatile keyword indicates that the variable can be modified by the hardware, OS, or concurrently running thread. When a variable is marked as volatile, the system always reads the current value of the variable at the point it is requested. If a variable is not volatile, it is possible that the CLR might decide that it is more efficient to use a cached value instead of reading a fresh copy. In addition, a volatile variable is written immediately. Here is how you would declare a volatile field:

public volatile int i;

while

Much like the do statement covered previously, this keyword declares a loop that executes until the expression evaluates to false. Listing A.56 illustrates a while statement.

Listing A.56. Using while
public static void Main()
{
    string input;
    bool stop = false;
    Console.WriteLine("Starting loop.");
    while(!stop)
    {
        Console.Write("Input . . .");
        input = Console.ReadLine();
        if(input[0] == 'B')
            stop = true;
    }
}

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.145.111.125