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.
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 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.
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.
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.
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.
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.
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#.