|
Data
types are the most basic elements of any computer language.
C# offers the usual data types (built-in as well as user-defined)
that one expects in a modern language. In this article, we
will discuss user-defined data types like classes and structures,
and a few other important topics related to data types in
C#.
Classes
A class is a user-defined data type that enables the combination
of data and functions that operate upon data in one entity.
Generally, data is hidden from the user and functions provide
an interface to use that data. The following program shows
how to declare and use a class.
using System;
class sample
{
private int i, f ;
public void setdata ( int ii, int ff )
{
i = ii ; f = ff ;
}
public void displaydata( )
{
Console.WriteLine ( "{0} {1}", i, f ) ;
}
}
Here, we have declared a class sample. i and f are called
data members of class sample. setdata( ) and displaydata(
) are called member functions or methods of class. C++ programmers
must note that a class declaration does not end with a semicolon
(;). The private written while declaring data members (or
member functions) implies that they can be accessed only in
the methods of class, not from outside the class. On the other
hand, the public keyword specifies that the methods can be
accessed both from inside as well as from outside the class.
public and private are called access specifiers.
We can create an object of sample class and call the methods
as shown below.
sample s = new sample( ) ;
s.setdata ( 12, 12.5 ) ;
s.displaydata( ) ;
The statement sample s = new sample( ) creates an object of
class sample and stores its address in s. So to say, s is
a reference to the object. Methods of a class can be accessed
only using its reference. So, we have used s to call displaydata(
) and setdata( ) methods.
Value Types & Reference Types
In C# data types are classified into two categoriesvalue
types and reference types. The difference between value type
and reference type is that the variables of value type are
allocated on stack, whereas, variables of reference type are
allocated on heap. Secondly, the variable of value type contains
data, whereas, variable of reference type contains the address
of the memory location where data of that variable is stored.
Among built-in data types, all the types of integers, floats,
doubles, decimals, chars and bools are value types, whereas,
the string and object are reference types. Among user-defined
data types, classes, interfaces and delegates are reference
types, whereas, structure is a value type.
Memory allocated for objects of value types is freed when
they go out of scope. Memory allocated for objects of reference
types is freed when they are no more being referenced.
Both the value and reference types have advantages and disadvantages.
Memory allocation on stack is faster than that on heap. So,
if the object is small, we must use a value type rather than
a reference type. On the other hand, if the object is big
we must avoid declaring it as a value type. Because, if we
assign it to any other object, its whole contents would get
copied, consuming additional memory. As against this, in case
of a reference type only the reference is copied rather than
the whole object.
Boxing and Unboxing
Boxing is the process of converting the value type (int, float,
struct, etc) into reference type (objects). On the other hand
unboxing is converting a reference type into a value type.
For example,
int i = 10 ;
object o = i ; // boxing
i = ( int ) o ; // unboxing
Boxing allocates memory for the value being boxed on heap,
copies the value into this memory and stores its reference
in an object type. Consider the following code.
int i = 12 ;
Console.WriteLine ( The value is {0} , i ) ;
The WriteLine( ) method is written to accept objects. When
we pass a variable of value type, int in this case, it gets
boxed into an object. Using this object a method ToString(
) is called, which returns the string equivalent of the value
stored in a variable. WriteLine( ) then displays this string.
Primitive Data Types
Having taken a look at user-defined types, let us now switch
over to primitive data types. Primitive data types in C# are
slightly different than they are in C/C++. The primitive data
types in C# are mapped to underlying structures defined by
the .NET base class library. This is done to ensure that code
written in C# can be used in other .NET compliant languages.
The following table lists the primitive data types and structures
they are mapped to.
The data types object and string are mapped to the System.Object
and System.String class respectively.
Type Conversion
C# is a strictly typed language. This avoids accidental loss
of value stored in a variable. Still, sometimes we may want
to type cast a variable into another. For this, C# supports
implicit and explicit type conversions. Implicit type conversion
is allowed so long as there is no loss of data. If we store
a short in an int or a long there is no loss of data because
a short value can easily be accommodated in an int or a long.
The reverse is not allowed because an int can contain a value
greater than what a short can accommodate and so, there is
a possibility of loss of data.
In
short, C# allows widening conversion but does not allow narrowing
conversion implicitly. If we want to convert a data type into
another for which implicit conversion is not possible, we
can do so by type casting. For example,
float f = 20.45f ;
int i ;
i = ( int ) f ;
Here, we would lose the value after the decimal point. So,
the value of i would now be 20.
Namespaces
Namespaces are used to hold a collection of related classes.
They help in avoiding naming conflicts. For example, two programmers
may design a class called books. If a user uses the class
library created by these programmers, then there may be a
conflict between these two classes. Namespace avoids this
conflict. The following code snippet shows how.
namespace Library
{
// definition of class books
}
namespace Shop
{
// definition of class books
}
To instantiate the object of books class we have to write
Library.books lb = new Library.books( ) ;
Shop.books sb = new Shop.books( ) ;
Thus, mentioning the name of namespace clearly indicates which
books class the user wants to refer to. Instead of mentioning
such a fully qualified name, we can use a using directive,
which makes available all the classes defined in a namespace
into the current scope. The statement
using Library;
will make available all the classes from the Library namespace.
This is known as importing classes. This is why the statement
using System is written at the beginning of a program. It
imports all the classes written in System namespace. Now we
have to simply say,
books lb = new books( );
|
Data type |
Mapped to |
Data type |
Mapped to |
|
sbyte |
System.SByte |
ulong |
System.UInt64 |
|
byte |
System.Byte |
char |
System.Char |
|
short |
System.Int16 |
float |
System.Single |
|
ushort |
System.UInt16 |
double |
System.Double |
|
int |
System.Int32 |
bool |
System.Boolean |
|
uint |
System.UInt32 |
decimal |
System.Decimal |
|
long |
System.Int64 |
|
|
 |
Yashavant
Kanetkar, one of the first Express Computer columnists,
is an established software expert, speaker and author
with several best-sellers to his credit, including titles
like “Let Us C” and the “Fundas” series. Contact him at
kanet@nagpur.dot.net.in |
|