Types in C#


This article has been excerpted from book "Visual C# Programmer's Guide"

There are two kinds of types in C#: reference types, which denote a memory location of the actual data, and value types, which reference the actual data. For example, if you define a reference type called aType, it would hold an address of memory where the actual data would be stored. If you define aType as a value type, it would contain the actual value, with no indication of the memory address where the value is stored.

Reference and value types differ in some important ways that are summarized in Table 5.2.

table5.2.gif

Table 5.2: Reference and Value Types

Value types include simple (char, int, bool, etc.), enum, and struct types; reference types include class, interface, delegate, and array types. Let's explore these types in more detail.

Value Types

Value types are declared by using their default constructors. In most cases, you use the new keyword to call the default constructor of a value type; but for some simple types, you don't even have to call the new keyword.

The default constructor of value types returns a zero-initialized instance, so you don't have to initialize a type when you define it. For example, the output value of both int1 and int2 in Listing 5.5 is 0.

Listing 5.5: ValueTypeTest.cs, Value Types Example


using
System;
public
class ValueTypeTest

{
    public static void Main()
    {
        // integer int1 and int2 initialization with 0
        int int1 = 0;
        int int2 = new int();
        Console.WriteLine(int1.ToString());
        Console.WriteLine(int2.ToString());
        Console.ReadLine();
    }
}


output_zero.gif

Output of listing 5.5 is 0.

The value types can be categorized as simple types, struct types, and enum types.

Simple Types

Simple value types include the traditional simple types listed in Table 5.3.

table5.3.gif

Table 5.3: Value Types

Simple types have a reserved keyword corresponding to one class of Common Language Specification (CLS) type defined in the System class. For example, keyword int represents System.Int32 type, and keyword long represents System.Int64 type. You can use either the C# shorthand-type keywords or the direct CLS types.

Note that you use suffixes for explicit type determination on demand. If you do that appropriately (as shown), you avoid compiler-selected automatic type conversions.


double
dblMyValue1 = 3.14d;

When defining a variable and assigning a value to it, use the m suffix (as shown) to denote a decimal value:

decimal decMyValue2 = 1.234567890m;

If you omit the m, the variable will be treated as type double by the compiler before it is assigned.

Structs

The struct, another kind of value type, can declare constructors, constants, fields, methods, properties, indexers, operators, and nested types. The main idea of using a struct is to create lightweight objects similar to a class. You can conserve memory using a struct because no additional references are created, as is needed in the case of class objects. When declaring arrays containing thousands of objects, this makes quite a difference in terms of resources.

Listing 5.6: Struct.cs, Struct Example


//example struct

using
System;
struct
StdRecord

{
    public string stdName;
    public string stdAddress;
    public int stdID;
}


class
Test
{
    public static void Main()
    {
        StdRecord rec;
        rec.stdName = "FirstName";
        rec.stdName = "LastName";
        rec.stdAddress = "Bank Street, NY";
        rec.stdID = 12794;
        Console.WriteLine("Student Name :" + rec.stdName);
        Console.WriteLine("Student Address :" + rec.stdAddress);
        Console.WriteLine("Student ID :" + rec.stdID);
        Console.ReadLine();
    }
}


The main use of struct types is to create your own data types. For example, the code in Listing 5.6 is used to generate a student record type containing a student name, address, and ID, as displayed in Figure 5.3.

fig_5.3.gif

Figure 5.3: Display Generated by Listing 5.6

Enum Types

The enum type is a set of named enumerated constants. Enums are generally used to give a meaningful name to a set of commonly used numeric values. Days in a week or months in a year are two suitable examples for the enumerations shown here.

enum
WeekDays {Sun, Mon, Tue, Wed, Thur, Fri, Sat};
enum
YearMonths {Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec};

Enum types are limited to long, int, short, and byte; the compiler does not recognize any other enum type. The default value is int. Note that you cannot convert basic types to enum types or vice versa. You have to cast them explicitly. Examples of the enum type follow:

// Sun is 0, Mon is 1, Tue is 2, Tue is 3 and so on.

enum
WeekDays { Sun, Mon, Tue, Wed, Thu, Fri, Sat};
// Sun is 5, Mon is 6, Tue is 7, Wed is 8 and so on.

enum
WeekDays { Sun=5, Mon, Tue, Wed, Thu, Fri, Sat };
// Sun is 5, Mon is 9, Tue is 6, Wed is 0 and so on.

enum
WeekDays { Sun =5, Mon =9, Tue =6, Wed=0};

Reference Types

A reference type is a reference to an instance of the type. In other words, a reference type is a memory address location that holds the actual value is stored. It is possible to have two variables holding the same memory address pointing to the same data. The main reference types are class, array, interface, delegate, and event types. Let's take a quick look at these types.

Class Type

The class type is used to represent real-life entities in object-oriented programming. A class can have members in the form of methods, properties, indexers, events, and delegates. You always declare and define all code fragments inside a class. Object and String are classes provided by the .NET framework. Listing 5.7 contains a simple example of class types.

Listing 5.7: Class Types Example


// Define A Class

public
class AClass : Object
{
    public void AMethod()
    {
        Console.WriteLine("A method");
    }
}


You can add methods, properties, indexers, delegates, and events to the class, as you'll see later in this chapter.

You can create an instance of a class type by using the operator new and then access the class type's public members by using the dot (.) operator used in Listing 5.8.

Listing 5.8: ClassType.cs, Class Types Example 2


using
System;
// Define A Class

public
class AClass : Object
{
    public void AMethod()
    {
        Console.WriteLine("A method");
    }
}


// Define B Class

public
class BClass : AClass
{
    public void BMethod()
    {
        Console.WriteLine("B method");
    }
}


public
class ValueTypeTest
{
    public static void Main()
    {
        AClass cls1 = new AClass();
        BClass cls2 = new BClass();
        cls1.AMethod();
        cls2.BMethod();
        Console.ReadLine();
    }
}


Figure 5.4 contains the screen output generated from the code in Listing 5.8.

fig5.4.gif

Figure 5.4: Screen Output from Listing 5.8.

Interface Type

An interface is a pure, virtual abstract class, useful for sharing functionality between similar classes. An interface defines a contract for the implementers of the interface; in other words, classes that implement an interface accept responsibility for defining the interface method body. You cannot instantiate an interface object. A class or struct that implements an interface must adhere to its contract. An interface may inherit from multiple base interfaces, and a class or struct may implement multiple interfaces.

Interfaces can contain methods, properties, events, and indexers only. The interface itself does not provide implementations for the members that it defines. The interface merely specifies the members that must be supplied by classes or interfaces that implement this interface. In fact, defining the methods in interfaces will cause a compile-time error. When you define the interface methods in a class, the method signature should be the same as the method declaration in the interface.

Listing 5.9 illustrates the functionality of interfaces through the ICopyable interface.

Listing 5.9: Interface ICopyable Example


using
System;

interface
ICopyable
{
    Object Copy(); // returns a reference to a copy of the object
}

class
SomeClass : ICopyable
{
    Int32 i;
    public SomeClass(Int32 i)
    {
        this.i = i;
    }

    public Object Copy()
    {
        return new SomeClass(i);
    }
}


class
ExampleApp
{
    static void Main()
    {
        SomeClass cls1 = new SomeClass(19);
        SomeClass cls2 = (SomeClass)cls1.Copy();
        // note cast necessary
    }
}


Delegate Type

A delegate type encapsulates a method with a certain signature. Delegates, the type-safe and secure version of function pointers, are commonly used for the implementation of callback functionality. This is a new feature. A common usage of the delegate type is class events. Delegates allow you to specify what the function you call looks like without having to specify which function to call. The declaration for a delegate looks just like the declaration for a function, except that you declare the signature of functions that this delegate can reference.

In the delegate application in Listing 5.10, the class MsgClass contains no specifics about the implementation of the Messenger function besides the function signature.

The class ExampleApplication can "delegate" the Messenger functionality to the designated method at runtime.

Listing 5.10: Delegate.cs, Delegate Example


// example delegate application

using
System;

public
class MsgClass
{
    public delegate void Messenger(string message);
    public void MessageProcess(Messenger myMessenger)
    {
        if (myMessenger != null)
            myMessenger("MessageProcess () begin");
        // other stuff here...
        if (myMessenger != null)
            myMessenger("MessageProcess () end");
    }
}


class
ExampleApplication
{
    static void Sender(string s)
    {
        Console.WriteLine(s);
    }
    public static void Main()
    {
        MsgClass myMsgClass = new MsgClass();
        MsgClass.Messenger msg = new MsgClass.Messenger(Sender);
        myMsgClass.MessageProcess(msg);
        Console.ReadLine();
    }
}


The screen output of Listing 5.10 appears in Figure 5.5.

fig_5.5.gif

Figure 5.5: Screen Output from Listing 5.10

Event Type

The event keyword allows you to specify a delegate to be called upon the occurrence of a particular event in your code. Listing 5.11 provides an example of this use of an event type. The delegate can have one or more associated methods to call when your code indicates the event has occurred. An event in one program can be made available to other programs that target the .NET runtime. Properties and events, which are central to component-based programming, are supported directly by the .NET framework.

Listing 5.11: Event.cs, Event Example


// example event application

using
System;

public
delegate void MyDelegate(); // delegate declaration

public
interface IFire
{
    event MyDelegate MyEvent;
    void FireAway();
}


public
class MyClass : IFire
{
    public event MyDelegate MyEvent;
    public void FireAway()
    {
        if (MyEvent != null)
            MyEvent();
    }
}

public
class MainClass
{
    static private void f()
    {        Console.WriteLine("This is called when the event fires.");
    }
    static public void Main()
    {
        IFire ifire = new MyClass();
        ifire.MyEvent += new MyDelegate(f);
        ifire.FireAway();
        Console.ReadLine();
    }
}


Figure 5.6 contains the output generated by the event type example in Listing 5.11.

fig_5.6.gif

Figure 5.6: Screen Output from Listing 5.11

Array Type

An array type is a sequential set containing an indexed list of objects. Arrays can also contain an ordered set of values. All of the elements must be of the same base type. An array can be one-dimensional or multidimensional.

In C#, the lower index of an array starts with 0 and the upper index is the number of items minus one. You can even make an array of structures or your custom data types, as Listing 5.12 illustrates.

Listing 5.12: Array Example


        Int32[] MyIntArray = new Int32[] { 1, 2, 3 };
        Int32 intMyValue = MyIntArray[2];
        // intMyValue stores 3 after this line


You can also declare various arrays such as those shown in Listing 5.13.

Listing 5.13: Multidimensional Array Example


        Int16[,] myIntArray1 = { { 0, 1 }, { 2, 3 }, { 4, 5 } }; // 3 x 2 multidimensional array
        Int16[,] myIntArray2 = new int[5, 3]; // 5 x 3 array with empty elements
        Int16 intVar3 = 5;
        Int16[] myIntArray3 = new int[intVar3]; // variable-sized array initialization


The static function below uses the static method Clear to clear all the numbers in the array, starting from 0 through the length of the array.

System.Array.Clear(MyIntArray, 0, MyIntArray.Length);


Conclusion


See other articles on the website on .NET and C#.


Similar Articles
C# Corner
C# Corner started as an online community for software developers in 1999.