Awanish Welcomes You

awanish tripathi: Data Types(C# continued....)

Inspirational & Genius One and the Same

personality shapes your behavior

Tuesday, January 18, 2011

Data Types(C# continued....)

Net C# Data Types
Data is physically stored inside cells of memory. This memory could be physical memory (Hard disk) or logical memory (RAM). Any cell of memory is represented with a unique address. This address is more than some combination of numbers or symbols.
C# language provides for practically all the data types. These types can be divided in three categories: value types, reference types and pointer types.

There are some more basic concepts to be learnt before the discussion of the data types. This is about variables and constants. A Variable is a named cell of memory used for data storage. A Variable value can be changed anytime. Every variable must have a type and this type must be set before it is used. Qualifying a variable with a type is called as declaration of variable. The type of a variable is the most important aspect and it defines the behavior of variable. All variables can be divided into seven main categories depending on the context of usage:
1. Static variables
2. Variable of instance
3. Array's elements
4. Parameters given by reference
5. Parameters given by value
6. Returned values
7. Local variables.
Static Variables will be alive throughout the life of a program. It can be declared using static modifier.
An Instance variable is a variable declared without static modifier. Usually it is declared inside a class or structure definition.
Parameter Values can be viewed as input parameters into methods:
public static void Sum(int a, int b)
{
Console.WriteLine("The sum of elements {0} and {1} is {2}",a,b,a + b);
}
This code writes in console values of variables a, b and their summary value. Now if the values of these parameters are modified inside the method, this change will not be reflected inside the main function. It is because the compiler creates copies of them when it passes them as value types. This ensures that their original values are not modified.
Instead if one wants to modify the parameter variables inside the function, C# has something called Reference variables.Reference variables also have a modifier out which can be used before their type. Look at the following example:
public static void SumRef(ref int a, ref int b)
{
a = 4;
b = 6;
Console.WriteLine("The sume of elements {0} and {1} is {2}",a,b,a + b);
}
Now this method modifies the value of variables a and b with values 4 and 6. These values are retained even after the execution of the function gets completed.
If the parameters need to be returned then they can be qualified with out modifier or as returned parameter in method definition. Here is an example of both of them, in which both of them return the same value:
public static int SumOut(int a, int b, out int sum1)
{
sum1 = a+b;
Console.WriteLine("The sum1 of elements {0} and {1} is {2}",a,b,a+b);
return sum1;
}
In main function it must be called in the next manner:
int sume ;
sume = SumeOut(2,2, out sume);
Constants in C#:
Constant type of data cannot be changed. To declare a constant the keyword const is used. An example for the constantdeclaration is: const double PI = 3.1415;
Values types in C#:
Value type stores real data. When the data are queried by different function a local copy of it these memory cells are created. It guarantees that changes made to our data in one function don't change them in some other function. Let see at a simple example:
public class IntClass
{
public int I = 1;
}
Here we have simple class that contains only one public data field of integer type. Now have a look on its usage in main function:
static void Main(string[] args)
{
// test class
int i = 10;
int j = i;
j = 11;
IntClass ic1 = new IntClass();
IntClass ic2 = ic1;
ic2.I = 100;

Console.WriteLine("value of i is {0} and j is {1}",i,j);
Console.WriteLine();
Console.WriteLine("value of ic1.I is {0} and ic2.I is {1}",ic1.I,ic2.I);
Console.WriteLine();
}
Reference Types in C#:
In the above example, assume that First we have two value type i and j. Also assume that the second variable is initialized with the value of the first one. It creates new copy in memory and after it the values of these variables will be next:
i=10;
j = i;
There are a few more things written in the above example for explaining the Reference Types in C#. At first, the variable ic1 of IntClass is created using dynamic memory allocation. Then we initialize the variable ic2 with value of ic1. This makes both the variables ic1 and ic2 referring to the same address. If we change a value of ic2, it automatically changes the value of ic1.
Now, over to the discussions about the important value types used in C#. The category simple types contains some predefined or system types that also are commonly used in other programming languages. It contains integer types: byte, Sbyte, Long, Ulong, Short, Ushort, int, Uint. These common types differs only range of values and sign.
Next simple type is character type. To declare a variable of this type need use keyword char. It can take values of characters or numbers as 16-digit symbol of the type Unicode.
The Boolean type has only two values: true, false. But these values cannot be assigned with a 0 or 1 as in C++ language.
Next category of simple types is floating point types. It contains two types float and double. Float type can get values in range from 1.5*10-45 to 3.4*1038. Double type has range of values from 5.0*10-324 to 1.7*10308.
A structural value types are struct and enum. Struct is a the same as class but it uses real values not references. The following code snippet contains the definition for struct:
Struct Point3D
{
public float m_x;
public float m_y;
public float m_z;

public float [] GetArray()
{
float [] arr = new float[3];
arr[0] = m_x;
arr[1] = m_y;
arr[2] = m_z;
return arr;
}
}
The above is declaration for a simple structure of real 3D point. As you see a class declaration looks very similar to the struct except that the class also has a constructor.

Enumerated types can be used to create some set of identifiers that can have values of simple type. Let us see at example of enum type:
public enum Days
{
Monday,
Tuesday,
Wensday,
Thursday,
Friday,
Saturday,
Sunday
}
In example there are enum that has days of week names. The values of days by default are in range from 0 to 6.
Common types in C#:
Object in C# language is universal; it means that all supported types are derived from it. It contains only a couple of methods: GetType() - returns a type of object, ToString() returns string equivalent of type that called.
Next type is class. It is declared in the same manner as structure type but it has more advanced features.
Interface is an abstract type. It is used only for declaring type with some abstract members. It means members without implementations. Please, have a look at piece of code with a declaration for a simple interface:
interface IRect
{
int Width
{
get;
set;
}

int Height
{
get;
set;
}

int CalculateArea();
}
The members of interface can be methods, properties and indexers.
Next reference type to be dealt is delegate. The main goal of delegate usage is encapsulation of methods. It most like at pointers to function in C++.
String is common type that is used in almost all programming languages of high level. An example of string declarationand initialization:
string s = "declaration and init";
The last very used reference type is array. Array it is set of elements that have the same type. Array contains list of references on memory cells and it can contain any amount of members. In C# there are three types of arrays: one-dimensional, two-dimensional and jagged array.
So, this covers almost all types used in C#. All these types can be cast to another type using special rules. An implicit casting can be done with types when values of variables can be converted without losing of any data. There is special type of implicit casting called boxing. This enables us to convert any type to the reference type or to the object type. Boxing example:
// boxing
char ch = 'b';
object obj = ch;
Console.WriteLine("Char value is {0}",ch);
Console.WriteLine("Object value is {0}",obj);
Console.WriteLine();
This piece of code prints the same values of integer type variable and object type variable. The opposite process to the boxing is un-boxing. An example for un-boxing is as follows.
// unboxing
float q = 4.6f;
object ob = q;
Console.WriteLine("Object value is {0}",ob);
float r = (float)ob;
Console.WriteLine("Float value is {0}",r);
So, it is main item of common data type creating and using. All sources are attached. To compile and run it need to run .NET command line. Just type: csc DataTypes.cs. It creates DataTypes.exe that can be run as standard executable file. You can download the sample code here.

Value and Reference Types
If you know C and C++ then you'll be familiar with the difference between local or auto variables and pointer/reference variables that are created on the heap. It's similar for C# value types and reference types.
The Heap and The Stack
Procedural programming languages that let you to create variables dynamically at run-time use two different areas of Ram for holding variables;. the stack and the heap. The heap is basically all unallocated memory.
The picture shows a rough layout of a program in memory. The first four areas (Program Code, Static Data, Uninitialized Data and Stack) are fixed in size when the application islinked and the heap is what's left over.
This is for each application, but because of the way a CPU virtualizes memory, each application runs in its own space and sees itself as having access to all available ram.
The stack holds value type variables plus return addresses for functions. All numeric types, ints, floats and doubles along with enums, chars, bools and structs are value types.
The heap hold variables created dynamically- known as reference variables and mainly instances of classes or strings. These variables are stored in two places; there's a hidden pointer to the place in the heap where the data is stored.
Another distinction between value and reference type is that a value type is derived fromSystem.ValueType while a reference type is derived from System.Object.
If you assign a value type variable to another then a direct copy of the value is made. But copying a reference type variable just makes a copy of the reference to the variable and does not affect the variable itself. This is like pointers in C and C++. You aren't copying what the pointer points to but making a copy of the pointer itself.
In C++ a struct is just a class with default public access. In C# it is like a class but much more limited and is a value type so is stored on the stack. It is closer to the original use of a struct in C where it was just a place to hold data. A struct cannot inherit from a struct not can it be inherited from.
To confuse matters slightly, a struct can contain constructors, constants, fields, methods, properties, indexers, operators, events, and nested types. A default constructor is provided by the compiler so you can initialize it with constructor type syntax. But you cannot write a default constructor for a struct yourself. Any constructors you write for a struct must have parameters.
Example 1
using System;
using System.Collections.Generic;
using System.Text;

namespace ex1
{
class class_test {
public int a=4;
public int b=2;


public class_test(int newa,int newb) {
a = newa;
b = newb;
}

public override string ToString() {
return a.ToString() + " " + b.ToString();
}
}

struct struct_test
{
public int a;
public int b;

public struct_test(int newa,int newb) {
a = newa;
b = newb;
}

// public override string ToString() {
// return a.ToString() + " " + b.ToString();
// }
}

class ex1
{
static void Main(string[] args)
{
struct_test t= new struct_test();
struct_test t2= new struct_test(8,7);
struct_test t3;
class_test c1 = new class_test();
Console.WriteLine("t = {0} ", c1);
Console.WriteLine("t = {0} ", t);
Console.WriteLine("t2 = {0} ", t2);
t3 = t;
Console.ReadKey();
}
}
}

This example demonstrates a simple struct type that has two public ints a and b. In a C# struct, everything is private unless explicitly declared public, the opposite of C++.
struct struct_test { public int a; public int b; public struct_test(int newa,int newb) { // constructor a = newa; b = newb; } public override string ToString() { return a.ToString() + " " + b.ToString() ; } }
The ToString() function overrides the function object.ToString(). All C# variables can do this. This provides an easy way to print out the value of a variable. By default though, for objects and structs, ToString() returns the name of the variable. You can override it, as I did to provide something more useful.

Unlike C++, a default constructor is supplied even when you write your own constructor but you aren't forced to call it. The compiler will complain though if you try to use a variable that it knows has not been initialized.
struct_test t= new struct_test() ; // calls the default constructor struct_test t2= new struct_test(8,7) ; // calls the constructor I wrote struct_test t3; // Leaves the object uninitialized
These are three ways of creating an instance of the object as shown above. If you attempt to read any field in t3, the compiler will complain. It's a compile error to read uninitialized variables. The built in default constructor initializes all fields to zero (0 for ints, 0.0 for floats,"" for strings, false for bool) etc.
t3.a = 8; // compiler ok int b= t3.b; // error - accessing uninitialized variable
This line
Console.WriteLine("t2 = {0} ", t2) ;
calls the t2.ToString() function which outputs 8 7.
Why Use Structs?
Because they are somewhat faster than classes at runtime, due to being directly accessed. Rather than use a full class for data structures, a struct is often more appropriate. Just how much faster though is a struct than a class? Example 2 gives an idea.
D
Using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;

namespace ex1
{
class class_test {
public int a;
public int b;

public class_test(int newa,int newb) {
a = newa;
b = newb;
}
}

struct struct_test
{
public int a;
public int b;

public struct_test(int newa,int newb) {
a = newa;
b = newb;
}
}

class ex1
{
static void Main(string[] args)
{
Stopwatch st = new Stopwatch();
Console.WriteLine("Started");
int total = 0;
st.Start();
for (int i = 0; i < 100000000; i++)
{
struct_test c1 = new struct_test(i,i);
//class_test c1 = new class_test(i, i);
int a = c1.a;
total += a;
}
st.Stop();
Console.WriteLine("Elapsed = {0} Total={1}", st.Elapsed.ToString(),total);
Console.ReadKey();
}
}
}

This loops 100 million times creating an object from either a class or a struct depending on which of the two lines in the loop is commented out. There's a bit of code to copy the value out of the object and total it up, thus ensuring that the object isn't optimized out because it's not used. The execution times are
1. Class 3.6 seconds.
2. Struct 1.4 seconds.
So if you can use a struct rather than a class, do so. It will make a bit of a difference.

The main reference type is object which is an instance of a class. The other one is string.
The constructor for a reference type allocates memory in the heap and then supplies a reference to this. C# hides the underlying details and prevents the possibility of C/C++ nullpointer problems.
However, unlike a value type, a reference type can be null.

DExample 3

using System;
namespace ex1
{

class test
{
public int a = 9;
}

class ex1
{
static void Main(string[] args)
{
test t=null;
t.a = 5;
Console.ReadKey();
}
}
}

But the compiler will usually stop you doing silly things. Objects in C# are generally easier to work with than in C++.
using System; namespace ex1 { class test { public int a = 9; } class ex1 { static void Main(string[] args) { test t=null; t.a = 5; Console.ReadKey() ; } } }
This compiles and runs, up to the t.a = 5; assignment where it falls over as t is null. The = null makes the compiler happy that t has a value, even if at runtime it's not valid. Try removing the = null and the compiler will flag the error.

Value types hold data, but reference types i.e. classes are meant to control how applications behave. The use of the two should be distinguished early on. If you usestructs and then later change them to classes, you may introduce some nasty bugs. Why? Because if you pass a struct by value as a function parameter then a copy of it is made in the function, and that copy used. The original struct is left unchanged unless the keyword ref is added to the call and the definition.
public struct t1 { public int Total; } public static int AddFive( t1 x) { x.Total += 5; return x.Total; }
In this example
(Example 4_1)
using System;

namespace ex1
{
class ex1
{

public struct t1
{
public int Total;
}

public static int AddFive( t1 x)
{
x.Total+= 5;

return x.Total;
}

static void Main(string[] args)
{
t1 t = new t1();
t.Total = 0;
int x = AddFive( t);
Console.WriteLine("x={0}", x);
Console.WriteLine("total={0}", t.Total);
Console.ReadKey();
}
}
}

x is a struct and is passed into AddFive. If x.Totalwas 0 upon entry then AddFive() will return 5 but x.Total will still be 0. Now change t1 to a class and because it is a reference type, x.Total will be 5 when AddFive() exits.
Boxing
Originally from Java, the concept of boxing is about storing a value type variable in a reference variable.
int i = 99; object t=(object)i; Console.WriteLine("Value of t ={0}",(int)t) ; Console.WriteLine("Value of t ={0}",t) ; Console.ReadKey() ;
This wraps the variable i in an object t i.e. inside a box. Remember all types ultimately derive from System.object.
Note - Boxing is a relatively slow process. According to Microsoft it takes 20 times as long as an assignment. This is because an object has to be created, then the valuetype variable copied into it. The opposite is unboxing, which is about four times as slow as assignment.
When would You Use Boxing?
The answer is you wouldn't if you can help it. If C# 1.0 and 1.1, it made possible null value value types (by boxing them as reference types) but with the nullable types in .NET 2.0 that is no longer needed.
In a class there are two types of fields and functions: instance and static. Instance fields are created when an instance of the class is created. Static fields apply only to the class itself. No matter how many instances of a class there are, there is only one instance of that classes' static fields.
Example 4.
This has a class test with a default constructor and a second constructor that copies data from another instance of the class. The private static int field has an id assigned to each instance object as it is created. If you step through the code, when the line
test x2 = new test(x) ;
is executed, you'll notice that the two lines
public object y=0; public object objid = nextid() ;
are run before the second constructor
test(test copy)
is entered.
The static function nextid() returns the value of the static field id and postincrements it. When you are learning objects and classes, the concept of static fields and functions is a bit alien because they apply to the type not an instance. A static class can exist without any instance fields or members.




Example 6.

using System;

namespace ex1
{
class ex1
{

static class test3 {

private static int x=8;

public static int X {
get {
return x;
}

set {
x=value;
}
}

static test3()
{
Console.WriteLine("Static Constructor Called");
}
}


static void Main(string[] args)
{
test3.X = 9;
Console.WriteLine("Value of test3.X ={0}",test3.X);
Console.ReadKey();
}
}
}

This has a static class test3. This can only have static members as no instances can be created. Members, and properties are accessed by the name of the class itself.
test3.X = 9;
Here X is a static property. Because test3 is a static class, there can be no instance members and everything must be declared static. If you put breakpoints on the static fieldx and the static constructor body you can see that those are executed sometime before the assignment takes place.

Download Example 7.

using System;

namespace ex1
{
class ex1
{

public static int GetValue(string Name)
{
Console.WriteLine("GetValue for {0}",Name);
return 99;
}

public class a {


int aint = GetValue("aint");
static a () {
Console.WriteLine("Static Constructor a");
}
static int staint = GetValue("staint");
public a () {
Console.WriteLine("Constructor a");
}
}

public class b : a
{
static int stbint = GetValue("stbint");
int cint = GetValue("bint");

static b () {
Console.WriteLine("Static Constructor b");
}

public b () {
Console.WriteLine("Constructor b");
}
}

public class c : b
{
static int stcint = GetValue("stcint");
int cint = GetValue("cint");
static c()
{
Console.WriteLine("Static Constructor c");
}

public c(int v)
{
stcint = v;
}

public c() : this(1)
{
Console.WriteLine("Constructor c");
}
}

static void Main(string[] args)
{
c obj = new c();
Console.ReadKey();
}
}
}

Example 7 shows three Classes a,b c such that a is the ancestor class and b is derived from a and c from b. All three classes have a default static constructor as well as a default instance constructor and two fields, one static, one instance.
All fields have initializers on them which just return an int via a call to a static function that outputs the name of the field. This example shows the order in which fields are initialized and constructors (both static and instance) are called. The output is shown below. Fields are named to help reveal their nature- cint (int in class c) and stcint, a static int in class cetc.
GetValue for stcint Static Constructor c GetValue for cint GetValue for stbint Static Constructor b GetValue for bint GetValue for staint Static Constructor a GetValue for aint Constructor a Constructor b Constructor c
Forgetting about initializers for now, it's interesting to note that static constructors are called in the opposite order to instance constructors. All of this happens when this line is executed.
c obj = new c();
Instance constructors are responsible for initializing their part of the instance and this is always in the order from base to the bottom derived class. The instance of b inherits from aso a is initialized then b then c. The compiler adds a hidden call to call the derived classes instance constructor. So c() calls b() which calls a().
C# supports a constructor initializer list syntax not dissimilar to that of C++ except you can only initialize the base instance (perhaps adding in parameters) or the current instance class (through the use of the word this) Adding this code in below, and explicitly calling the base class does not affect the program as this is what the compiler does behind the scenes.
public c() : base() { Console.WriteLine("Constructor c") ; }
You can even add in a call to another constructor, as in below. The single parameter instance constructor is called before the default constructor.
public c(int v) { stcint = v; } public c() : this(1) { Console.WriteLine("Constructor c") ; }
The use of base and this apply only to instances and not static classes. There is no instance in a static class.
Static Constructors and Initializers So why were the static constructors and initializers and the instance initializers called in the order c, b ,a and not the same order as the instance constructors? Because that is the order that the classes are accessed. The first class created was c. What actually happens is this.
1. Static Field Initializers are executed. These might be needed in the static constructor.
2. Static Constructor is called.
3. The instance initializer is called.
4. The base class is accessed, repeating steps 1-3.
Some Simple Rules to Remember
• Field Initializers are called before Constructors.
• Static Initializers and Constructors are called once before any instances are constructed.
• Statics are called (in a class hierarchy) in the order that classes are used.
• Instances are constructed in a hierarchy starting with the ancestor class.

This example uses a struct, a class and a static field. Card games are popular on the web and example 8 demonstrates how to setup and use a pack of cards.
Download Example 8

using System;

namespace ex1
{
class ex1
{

enum CardValue {Two,Three,Four,Five,Six,Seven,Eight,Nine,Ten,Jack,Queen,King,Ace};
enum CardSuit {Hearts, Clubs, Diamonds, Spades };
static char[] SuitChars= new char[4]{'H','C','D','S'};
static char[] SuitValues= new char[13]{'2','3','4','5','6','7','8','9','T','J','Q','K','A'};

private struct CardType {
public static bool ShortCard=false;

public CardValue Value;
public CardSuit Suit;

public override String ToString()
{
if (ShortCard)
return SuitValues[(int)(Value)].ToString() +
SuitChars[(int)Suit];
else
return Value.ToString()+' '+Suit.ToString();
}
}

class Deck
{
private Random r= new Random();
private int topcount;

private CardType [] cards = new CardType[52];

public CardType this[int index] {
get { return cards[index]; }
set { cards[index]= value; }
}

private int FindIndex(string ShortCardValue)
{
int result = -1;
for (int index = 0; index < 52; index++)
{
if (cards[index].ToString() == ShortCardValue)
{
result = index;
break;
}
}
return result;
}

public CardType this[string value]
{
get { return cards[FindIndex(value)]; }
}

public Deck()
{
int index=0;

foreach (CardSuit Suit in Enum.GetValues(typeof(CardSuit)))
{
foreach (CardValue Value in Enum.GetValues(typeof(CardValue)))
{
cards[index].Value = Value;
cards[index].Suit = Suit;
index++;
}
}
ShuffleDeck();
}

public void ShuffleDeck() {
for (int index=0;index <500;index++) {
int first=r.Next(52);
int second= r.Next(52);
while (first == second) {
second=r.Next(52);
}

CardType temp=cards[first];
cards[first]=cards[second];
cards[second]= temp;
}
}

public CardType DrawCard()
{
if (topcount == 0)
{
ShuffleDeck();
topcount = 52;
}
return cards[--topcount];
}
}

static void Main(string[] args)
{
CardType.ShortCard = true;
Deck MyCards = new Deck();
for (int i = 0; i < 52; i++)
{
Console.WriteLine("Card {0} is {1}", i+1, MyCards[i]);
}
if (CardType.ShortCard)
{
CardType C = MyCards["2D"];
}
Console.ReadKey();
}
}
}

I've chosen a struct for each playing card; there's little in the way of code apart from the overridden ToString() method. This uses a static bool ShortCard to output the cards in either long format E.g. King Spades or short, e.g. KS. This is a public static field in theCardType struct. Being static, it affects every card.
CardType.ShortCard = false; // false = long format
Enums are used for both the card values and suits. The Deck class holds an array of 52 cards and these are created by an initializer. A double loop then initializes the deck of cards. You can verify this by commenting out the ShuffleDeck() call and the cards will be printed in order. Two for loops would have done but this gave a chance to use the foreachconstruct. This iterates through all members of the CardSuit and CardValue enums.
int index=0; foreach (CardSuit Suit in Enum.GetValues(typeof(CardSuit))) { foreach (CardValue Value in Enum.GetValues(typeof(CardValue))) { cards[index].Value = Value; cards[index].Suit = Suit; index++; } }
The first foreach is the same as
for (CardSuit Suit = CardSuit.Hearts;Suit < CardSuit.Spades;Suit++)
But the foreach is all round better- you're not going to pick the wrong value in the For loop as I did. Hearts was the first enum value, but the Intellisense feature of the IDE kept displayed the available values in alphabetical order.

Continuing with the playing cards example, this demonstrates the use of an indexer. This is a way of accessing the Cards via an indexed property. Within the class Deck, cards is anarray but in the Main function, I access each card by using MyCards[ i ], yet MyCards is the actual instance of Deck. This property declaration is what does the trick.
public CardType this[ int index] { get { return cards[ index ]; } set { cards[ index ]= value; } }
The property member is defined thus
this[ int index ]
and is called an indexer, in this case it's an int called index. Each class or struct can have multiple indexers as long as the signatures are unique. The signature is the bit inside square brackets eg [int index]. You might for example want to find the position of a card in the deck and there is a second indexer provided with this signature
this [string value]
This calls a function FindIndex() to search the array for a matching short card, e.g. "2D". This only works if the ShortCard bool is set to true. If it is, then a card can be retrieved like this:
CardType C = MyCards["2D"];
Unlike other properties, this one always uses the keyword this (ie it refers to an instance of this class- this means it only works with instance objects and NOT static classes. Thesyntax is very similar to properties with get and set, but includes an indexed field. The general form is shown below, where the indexed field is called arr.
public T this[int i] { get { return arr[ i ]; } set { arr[ i ] = value; } }
Just like a property this includes get and set accessor methods to alter or access the private field array or structure. But you must use this for accessing the indexer.

No comments:

Post a Comment

Post a Comment