using block in C#.Net

  • using block in C# ensures correct use of IDisposable interface.
  • We can use using block only on the objects that implements IDisposable interface.
  • using block calls the dispose method of an object in a correct way and it also causes the object to go out of scope when dispose method of that object gets called.
  • using block gets converted to try..finally block after getting compiled to MSIL code. You can check MSIL code using ILDASM tool.
  • using block ensures that dispose method gets called even if an exception occurs.
  • Multiple type can be declared in using statement.

See below code sample for the same.

+
Code

using System;
 
namespace using_block
{
    class Program
    {
        static void Main(string[] args)
        {
            using (clsUseByUsingBlock obj1 = new clsUseByUsingBlock())
            {
                obj1.num = 2;
            }
        }
    }
 
    class clsUseByUsingBlock:IDisposable
    {
        public int num { getset; }
 
        public void Dispose()
        {
           //Cleanup activities
        }
    }
}

In above code sample, we have declared a class clsUseByUsingBlock which implements dispose method of IDisposable interface. We are used object of this class in using block. So at the background using block automatically calls the dispose method of our class, we don't need to explicitly call this dispose method.

This using block gets converted to try..finally block once code gets compiled. See below code for the same with try..finally block.

+
Code

clsUseByUsingBlock obj2 = new clsUseByUsingBlock();
try
{
      obj2.num = 2;
}
finally
{
      obj2.Dispose();
}

When you check actual MSIL code using ILDASM tool, it looks like below.


using block in C#

Error handling using Try Catch Finally block

In C#, try block followed by one or more catch blocks is used for handling run-time Exceptions (Error).

Below is the example of using try catch block.

+
Code
using System;
 
namespace tryCatchFinally
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                int i = 0;
                //error occured at this line.
                int res = 100 / i;
                Console.WriteLine(res);
            }
            catch (Exception ex)
            {
                Console.WriteLine("Following Error occured: \n\t" + ex.Message);
            }
            Console.ReadLine();
        }
    }
}


When we try to run above code,we get Attempted to divide by zero error while dividing 100 by 0 and from that line, control directly goes to catch block without executing next line of code in try block, and print an error at console.

By using try-catch block, we can show a user friendly message to users of our application.

We can declare more than one catch block for one try block. Depending on the error occurred in try block, corresponding catch block gets executed. See below example for the same.

+
Code

using System;
 
namespace tryCatchFinally
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                int i = 0;
 
                int[] j = new int[2];
 
                j[0] = 1;
                j[1] = 2;
                //You can't add 3rd element in array j, as its size is 2. We get Index out of range exception here.
                j[2] = 3;
 
                foreach (int m in j)
                {
                    Console.WriteLine(m);
                }
 
                //error occured at this line.
                int res = 100 / i;
                Console.WriteLine(res);
            }
            catch (IndexOutOfRangeException ex)
            {
                Console.WriteLine("Index of array j is out of range. You can add only 2 items in it.");
            }
            catch (DivideByZeroException ex)
            {
                Console.WriteLine("You can't devide a number by zero");
            }
            catch (Exception ex)
            {
                Console.WriteLine("Following Error occured: \n\t" + ex.Message);
            }
            Console.ReadLine();
        }
    }
}

In the above code, we have declared 3 catch block, 1st is handling Index out of range exception, 2nd handling Divide by zero exception and 3rd handling errors other than these errors (all errors). if we execute above code, as int array j has size 2, if we try to add 3rd element in it, we get index out of range exception there and control directly goes to 1st catch block printing error Index of array j is out of range. You can add only 2 items in it on console. If we get divide by zero error then control goes to 2nd catch block and if error other than these 2 errors gets occurred then 3rd catch block gets executed.

We have another block in our try catch block, finally block, which gets executed every time when control left from try/catch block irrespective of error occurred or not. So we can do any cleanup resource activities, closing connection activity in finally block.
Below is the syntax for the same. We can write try-finally block as well (excluding catch block).

+
Code

try
{
                               
}
catch (Exception ex)
{
                
}
finally
{
 
}

Abstract Classes in C#

  • Abstract classes are special type of classes that we can't instantiate.
  • It contains abstract methods/Properties that has no implementation like the methods/Properties that we declare in Interface and it also contains methods/Properties with implementation like normal class.
  • Class deriving from abstact class must provide implementation to the abstract methods/Properties. We have to use override keyword while implementing abstract method in derived class.
  • Like classes we can declare variables, constants, properties, constructors, destructors in abstract classes.
  • We can say that abstract classes are partially like interfaces.
Below is an example of Abstract class.

+
using System;
 
namespace Abstact_Class
{
    public abstract class abstactClass
    {
        //abstract method
        abstract public void abstractMethod();
 
        //normal method with implementation
        public void normalMethod()
        {
            Console.WriteLine("Normal method impemented in abstract class");
        }
    }
 
    public class derivClass:abstactClass
    {
 
        public override void abstractMethod()
        {
            Console.WriteLine("abstract method implemented in derived class");
        }
    }
 
    class Program
    {
        static void Main(string[] args)
        {
            derivClass derivCls = new derivClass();
            derivCls.abstractMethod();
            derivCls.normalMethod();
 
            Console.ReadLine();
        }
    }
}

In above code, We have declared abstract class abstactClass with one abstract method abstractMethod and one normal method, normalMethod with implementation provided.
We have derivClass which inherits abstractClass, Provide their own implementation for abstract method from abstract class along with we can access normal method declared in abstract class for our derived class.
See in program class's main method we declared variable of derivClass and accessed both the methods.

Now what is the use of abstract class? Let take an example from dot net framework.
In dot net framework, we have DbConnection  abstract class in System.Data.Common namespace.
If you check Definition of  DbConnection  class in dot net framework, you can see below abstract class Definition.

+
using System;
using System.ComponentModel;
using System.Data;
 
namespace System.Data.Common
{
    // Summary:
    //     Represents a connection to a database.
    public abstract class DbConnection : ComponentIDbConnectionIDisposable
    {
        protected DbConnection();
 
        public abstract string ConnectionString { getset; }
 
        public virtual int ConnectionTimeout { get; }
        
        public abstract string Database { get; }
        
        public abstract string DataSource { get; }
        
        protected virtual DbProviderFactory DbProviderFactory { get; }
        
        public abstract string ServerVersion { get; }
        
        public abstract ConnectionState State { get; }
 
        public virtual event StateChangeEventHandler StateChange;
 
        protected abstract DbTransaction BeginDbTransaction(IsolationLevel isolationLevel);
        
        public DbTransaction BeginTransaction();
        
        public DbTransaction BeginTransaction(IsolationLevel isolationLevel);
        
        public abstract void ChangeDatabase(string databaseName);
        
        public abstract void Close();
        
        public DbCommand CreateCommand();
        
        protected abstract DbCommand CreateDbCommand();
        
        public virtual void EnlistTransaction(System.Transactions.Transaction transaction);
       
        public virtual DataTable GetSchema();
        
        public virtual DataTable GetSchema(string collectionName);
        
        public virtual DataTable GetSchema(string collectionName, string[] restrictionValues);
        
        protected virtual void OnStateChange(StateChangeEventArgs stateChange);
        
        public abstract void Open();
    }
}

You can see in above code there are abstract methods/properties as well as normal methods, virtual methods and properties are also declared. The classes which are responsible for connecting to different type of databases are derived from this abstract class. If you check SqlConnection or OleDbConnection class, they both derived from this abstract class. See below class definition of SqlConnection class

+
using Microsoft.SqlServer.Server;
using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Data.Common;
using System.Diagnostics;
using System.Runtime.ConstrainedExecution;
using System.Security;
 
namespace System.Data.SqlClient
{
    // Summary:
    //     Represents an open connection to a SQL Server database. This class cannot
    //     be inherited.
    public sealed class SqlConnection : DbConnectionICloneable
    {
       
        public SqlConnection();
        
        public SqlConnection(string connectionString);
 
        public override string ConnectionString { getset; }
        
        public override int ConnectionTimeout { get; }
        
        public override string Database { get; }
        
        public override string DataSource { get; }
        protected override DbProviderFactory DbProviderFactory { get; }
       
        public bool FireInfoMessageEventOnUserErrors { getset; }
        
        public int PacketSize { get; }
        
        public override string ServerVersion { get; }
        
        public override ConnectionState State { get; }
        
        public bool StatisticsEnabled { getset; }

        public string WorkstationId { get; }
 
        public event SqlInfoMessageEventHandler InfoMessage;
 
        protected override DbTransaction BeginDbTransaction(IsolationLevel isolationLevel);
        
        public SqlTransaction BeginTransaction();
        
        public SqlTransaction BeginTransaction(IsolationLevel iso);
       
        public SqlTransaction BeginTransaction(string transactionName);
        
        public SqlTransaction BeginTransaction(IsolationLevel iso, string transactionName);
        
        public override void ChangeDatabase(string database);
       
        public static void ChangePassword(string connectionString, string newPassword);
        
        public static void ClearAllPools();
       
        public static void ClearPool(SqlConnection connection);
        
        public override void Close();
        
        public SqlCommand CreateCommand();
        protected override DbCommand CreateDbCommand();
        protected override void Dispose(bool disposing);
        
        public void EnlistDistributedTransaction(System.EnterpriseServices.ITransaction transaction);
        
        public override void EnlistTransaction(System.Transactions.Transaction transaction);
        
        public override DataTable GetSchema();
       
        public override DataTable GetSchema(string collectionName);
        
        public override DataTable GetSchema(string collectionName, string[] restrictionValues);
        
        public override void Open();
        
        public void ResetStatistics();
        
        public IDictionary RetrieveStatistics();
    }
}

If you see both classes, we have ConnectionString Property declared as abstract in DbConnection
class. Now each class have different ConnectionString for connecting to respective database. e.g. for above
SqlConnection class, we have ConnectionString defined for connecting to Sql Database. Same like for OleDbConnection class, we have different ConnectionString defined for connecting to other databases. So by using abstract class and deriving class from it, forces derived classes to use common naming convention across various classes but provide flexibility to give their own implementation. This ensures Code Maintainability.
Another importance of Abstract class is, We can declare and implement methods/properties in abstract class that are common to all derived classes. e.g. in our DbConnection class, we have method BeginTransaction() which handles transaction across all databases. Transaction method across all databases is same. So this method is common to all other derived classes. No need to write separate method for each derived class.

SQL-Server Concepts

Return all the tables in the database which user have created

USE YourDataBaseName
GO

SELECT *
FROM sys.Tables
GO

To get all the databases on a server, you can use the same technique, but just a bit different query.

USE Master
GO

SELECT *
FROM sys.Databases
GO

For a list of all tables on a server

sp_msforeachdb @command1='USE ?;SELECT * FROM sys.Tables'

Reset Identity Column Value in SQL Server

If you are using an identity column on your SQL Server tables, you can set the next insert value to whatever value you want. An example is if you wanted to start numbering your ID column at 1000 instead of 1.

First check what the current identify value is. We can use this command to do so:
DBCC CHECKIDENT (’tablename’, NORESEED)

For instance, if I want to check the next ID value of my orders table, I could use this command:
DBCC CHECKIDENT (orders, NORESEED)

To set the value of the next ID to be 1000, I can use this command:
DBCC CHECKIDENT (orders, RESEED, 999)

Note that the next value will be whatever you reseed with + 1, so in this case I set it to 999 so that the next value will be 1000.

Another thing to note is that you may need to enclose the table name in single quotes or square brackets if you are referencing by a full path, or if your table name has spaces in it.
DBCC CHECKIDENT ( ‘databasename.dbo.orders’,RESEED, 999)

Get all Open Transactions in SQL

Interface and Use of Interface

  • We create Interfaces using Interface keyword.
  • Just like a class, Interface contains methods, Properties, events, delegates but we can only define these terms in Interface and we don’t have implementation for that in an Interface.
  • Interface can’t contains Fields, constants, operators, constructors, destructors.
  • Interface members are public by default. We can’t explicitly define access specifiers on Interface members, if we do so, we will get compile time error. Also members should not be static.
  • Another class or struct who is using this interface, must provide implementation for all members of that Interface.
  • As we know that C# doesn’t support multiple class inheritance, We can achieve multiple inheritance using Interface.

Below is the Example for Interface

+
using System;
 
namespace Interfaces
{
    interface IMyInterface
    {
        void showMessage();
    }
 
    class Program : IMyInterface
    {
        public void showMessage()
        {
            Console.WriteLine("Interface method implemented");
        }
 
        static void Main(string[] args)
        {
            Program myProg = new Program();
            myProg.showMessage();
 
            Console.ReadLine();
        }
 
 
    }
}


In above code sample, We have declared interface IMyInterface and implemented it in Program class.

Now we know that C# doesn’t support multiple class inheritance. What is that mean? lets look at an example below.

+
using System;
 
namespace Interfaces
{
    class classA
    {
        public void Add()
        {
            Console.WriteLine("ClassA Add() method called");
        }
    }
 
    class classB
    {
        public void Add()
        {
            Console.WriteLine("ClassB Add() method called");
        }
    }
 
    class classC : classA, classB
    {
        public void Subtract()
        {
            Console.WriteLine("ClassC Subtract() called");
        }
    }
 
    class Program
    {
        static void Main(string[] args)
        {
            classC clsC = new classC();
            clsC.Add();
            Console.ReadLine();
        } 
    }
}

In Above code, We have created 2 class classA and classB both having same method declared Add(). Now suppose, for the time being, C# supports multiple inheritance, We have derived class classC which inherits both classA and classB, that means by using classC object we can access Add() method.
We have created Object of classC in our main method in Program class and we called Add() method using that object. Now in this case which Add() method gets called? There will be ambiguity in calling this method. This is the reason, C# doesn't allow multiple inheritance. If we compile above code, we will get compile time error saying Class 'Interfaces.classC' cannot have multiple base classes: 'Interfaces.classA' and 'classB'

Now see below code sample, where we achieved multiple inheritance using interface.

+
using System;
 
namespace Interfaces
{
    interface IClassA
    {
        void methodClassA();
    }
 
    class classA:IClassA
    {
 
        public void methodClassA()
        {
            Console.WriteLine("classA method gets called");
        }
    }
 
    interface IClassB
    {
        void methodClassB();
    }
 
    class classB : IClassB
    {
 
        public void methodClassB()
        {
            Console.WriteLine("classB method gets called");
        }
    }
 
    class classC:IClassA,IClassB
    {
        public void methodClassA()
        {
            new classA().methodClassA();
        }
 
        public void methodClassB()
        {
            new classB().methodClassB();
        }
    }
 
    class Program
    {
        static void Main(string[] args)
        {
            classC clsC = new classC();
            clsC.methodClassA();
            clsC.methodClassB();
 
            Console.ReadLine();
        }
    }
 }

In above code sample, classA and ClassB methods implements IClassA and IClassB respectively. In classC we have implemented interface IClassA and IClassB and called classA and classB's method directly by using objects of classA and classB.

Consider third case now, where we have two interface that have same method declared in it. Lets take an example below where we have two interfaces declared with same method name add()

+
using System;
 
namespace Interfaces
{
    interface InterfaceA
    {
        void add();
    }
 
    interface InterfaceB
    {
        void add();
    }
 
    class clsA:InterfaceA
    {
 
        public void add()
        {
            Console.WriteLine("clsA add() method gets called");
        }
    }
 
    class clsB : InterfaceB
    {
 
        public void add()
        {
            Console.WriteLine("clsB add() method gets called");
        }
    }
 
    class classAB:InterfaceA,InterfaceB
    {
 
        public void add()
        {
            new clsA().add();
        }
 
        void InterfaceB.add()
        {
            new clsB().add();
        }
    }
 
    class Program
    {
        static void Main(string[] args)
        {
            //sample 1
            InterfaceA clsA = new classAB();
            clsA.add();
 
            //sample 3
            InterfaceB clsB = new classAB();
            clsB.add();
 
            //sample 3
            classAB clsAB = new classAB();
            clsAB.add();
        }
 
 
    }
 
}

In the above case, When we implement both interface in classAB, We have to explicitly implement one of interface's add() method, just like in above code, we have implemented InterfaceB's add() method by prefixing interface name to it.

In the above code, if we want to call method of a respective class then create reference variable of that particular class's interface which will points to classAB object. See sample 1 in above code in Main method, where we want to call clsA's method. So we have created reference variable of interfaceA as class clsA implements InterfaceA.

Suppose, we Directly created reference variable of class clsAB and call the method add(), then by default first method that we written without interface name prefixed will get called i.e clsA's method. you can copy above code and check the final output.

If you see dot net framework, you can find all interfaces defined starting with letter 'I', e.g. IEnumerable, IEquatable, IComparable, IDisposable etc.

Properties in C# and use of Properties

Properties are special type of members, declared to read/write private Fields within a declared Type(Class, Struct).
Properties are used as if they are public fields within a declared Type.
Properties have set and get accessor in order to set value to a private fields and get the value of a private fields.
By using properties we can hide private members of our Type.
Properties simplify the code to read or set the data for private fields.
A value keyword is used to define the value assigned by set accessor.

Below is an example of use of property:

+
using System;
 
namespace Properties_in_CSharp
{
 
    public class Student
    {
        string _name;
        float _physics, _chemistry, _biology,_totalMarks,_percentage;
 
        
 
        public string Name
        {
            get
            {
                return _name;
            }
            set
            {
                if (string.IsNullOrEmpty(value))
                {
                    throw new Exception("Name should not be blank");
                }
 
                _name = value;
 
            }
        }
 
        public float PhysicsMarks
        {
            get
            {
                return _physics;
            }
            set
            {
                if (value <= 0)
                {
                    throw new Exception("Marks in Physics should be greater than zero");
                }
 
                _physics = value;
 
            }
        }
        public float ChemistryMarks
        {
            get
            {
                return _chemistry;
            }
            set
            {
                if (value <= 0)
                {
                    throw new Exception("Marks in Chemistry should be greater than zero");
                }
 
                _chemistry = value;
 
            }
        }
 
        public float BiologyMarks
        {
            get
            {
                return _biology;
            }
            set
            {
                if (value <= 0)
                {
                    throw new Exception("Marks in Biology should be greater than zero");
                }
 
                _biology = value;
 
            }
        }
 
        public float Totalmarks
        {
            get
            {
                return _totalMarks =_physics + _chemistry + _biology;
            }
        }
 
        public float Percentage
        {
            get
            {
                return (_totalMarks / 300) * 100;
            }
        }
    }
 
 
    class UseOfProperties
    {
        static void Main()
        {
            Student stud = new Student();
 
            stud.Name = "Sameer";
            stud.PhysicsMarks = 87;
            stud.ChemistryMarks = 90;
            stud.BiologyMarks = 70;
 
            Console.WriteLine("Name of Student : {0}", stud.Name);
            Console.WriteLine("\nMarks Obtained by {0}",stud.Name);
            Console.WriteLine("Physics : {0}",stud.PhysicsMarks);
            Console.WriteLine("Checmistry : {0}", stud.ChemistryMarks);
            Console.WriteLine("Biology : {0}", stud.BiologyMarks);
            Console.WriteLine("\nTotal Marks obtained : {0}",stud.Totalmarks);
            Console.WriteLine("Percentage Obtained : {0}",stud.Percentage);
 
            Console.ReadLine();
        }
    }
}

In above code sample, We have declared properties to get or set private fields declared with underscore(_) at the top. We can achieve this by creating functions as well, but in that case, we have to separately declare methods for getting and setting values for private fields and also have to call each method to get or set values. By declaring property, We can use same property name to get or set values.
See  value  keyword used in set accessor, Whatever value we assign to our proerty, say e.g. we have stud.Name = "Sameer", the value Sameer gets assigned to value variable in set accessor and from there we can assign that value data to our private fields(In this case _name = value).
).
Also, if you see Totalmarks property, It has only get accessor, that means we can only read the value of private variable.

Below is the output for our above code sample.

Properties in C#

Partial Classes and Partial Methods

By using Partial keyword we can partly devides our class,Struct, Interface into two or more files. Later when the application gets compiled all the files gets combined.

Splitting application code into several files is helpful,
  • When there is a large project development, we can devide our class into several different files so that it enables multiple programmers to work simultaneously on that class.
The best example of partial class is when we add new page in our web application or windows application in dot net, we can see 2 files gets added for our page/form.
For windows application, we have one Form1.cs file and another one is Form1.Designer.cs and if you check code behind of these files, you can see partial class defined there. In Form1.Designer.cs, we have definition of all controls that we add in our form and Form1.cs file contains all the events, custom code of our application. When these files gets compiled, they gets combined into one class.

Like we declare classes, Structs, Interfaces partial, we can declare partial methods as well. following are the conditions while declaring partial methods.
  • We can declare partial methods in partial type (Class,Struct) only.
  • partial method signature is defined in one part of partial type and implementation in other part of partial type.
  • Return type of partial method should be void.
  • We can't use access modifier on partial methods. They are private by default.
If we only declared partial method and not provided any impementation for that, then compiler will ignore the signature of that method.

See below sample code where class partialClass splits in two parts with partial keyword and also defined partial method ShowMessage in one part and implemented in second part.

+
using System;
 
namespace partial_class_and_methods
{
    //partial class part1
    partial class partialClass
    {
        partial void ShowMessage(string message);
    }
 
    //partial class part2
    partial class partialClass
    {
        partial void ShowMessage(string message)
        {
            Console.WriteLine("Partial method declaration with message" + message );
        }
    }
}


Structures in CSharp

1. Structure in C# is similar to the class. Just like class, We can encapsulate Fields, Properties, methods in structures.
2. By using Struct Keyword we can declare structure.
3. We can declare struct to represent lightweight objects such as int, enum, double, bool.
4. Struct is a value type.

Below is the example of struct.

+
using System;
 
namespace constructor_example
{
    class Program
    {
        static void Main(string[] args)
        {
            //use of struct 
            Car alto;
            alto.Company = "Maruti Suzuki";
            alto.Model = "Alto K10";
            alto.Year = 2005;
 
            Console.WriteLine();
 
            Console.WriteLine(" Company Name = " + alto.Company);
            Console.WriteLine(" Model Name = " + alto.Model);
            Console.WriteLine(" Launched in Year = " + alto.Year);
 
            //use of Class
            Cars cars = new Cars();
            cars.Company = "Bajaj";
            cars.Model = "xcd";
            cars.Year = 2004;
 
            Console.WriteLine();
 
            Console.WriteLine(" Company Name = " + cars.Company);
            Console.WriteLine(" Model Name = " + cars.Model);
            Console.WriteLine(" Launched in Year = " + cars.Year);
 
            Console.ReadLine();
        }
    }
 
    struct Car
    {
        public string Company;
        public string Model;
        public int Year;
    }
 
    class Cars
    {
        public string Company;
        public string Model;
        public int Year;
    }
}


In above code, I have declared a struct Car with fields like Company, Model, Year. See the syntax of declaring struct is same as class. I have also created class Cars in above example with same fields. You can see the difference there. We don't need to use new keyword while declaring variable of struct, but with class we should have to use new keyword in order to create variable of type class, otherwise compiler will give Object reference not found error.

Difference between Structure and Class
1. Structure is value type, Class is reference type.
2. We can use structure to represent lightweight objects, while classes are used to represent complex objects.
3. All structure elements are public by default, Class variables,constants are private by default.
4. Structures variables can not be initialized at the time of declaration, Class variables can be initialized.
5. Structure elements can't be declared as Protected, Class members can be declared.
6. Structures are not inheritable, Classes are inheritable.
7. Structure doesn't required constructor, Class can require Constructor.


Value Type and Reference Type variables

There are two types of memory available on disk while storing the variables that we declare - 1. Stack memory and Heap memory.

Value Type variables
1. Value type variables gets stored on Stack and stores data in its own memory location, i.e. both variable and data gets stored on stack.

2. When we copy data of one value type variable to another value type variable then 2 different copies of memory location gets assigned to these 2 variables.

3. All data types mentioned in our Data Type in C# section are of value type except string.

4. All structures that we declare in our program are value type even though its members declared are reference types. If you see int data type, it is a structure.

Reference Type variables
1. Reference type variables that we creates also gets stored on stack but the data associated with it gets stored on Heap, i.e. The variable that we declare contains reference of address for memory location of the data which is stored on heap and the variable points to that memory location.

2. Data type such as String, Array, classes, Interfaces, Delegates are all of reference types.

3. When we copy data of one reference type variable into another reference type variable then 2 different copies of these variables gets created on stack, but both these variables contains reference to same memory location on heap where the data gets stored.

Lets take a look at example below.

+
using System;
 
namespace examples
{
    class Program
    {
        static void Main(string[] args)
        {
            //value type variables
            int i;
            i = 3;
            Console.WriteLine("i = " + i);
 
            int j = i;
            Console.WriteLine("j = " + j);
 
            j = 4;
            Console.WriteLine("i = {0}, j= {1}", i, j);
 
            //reference type variables 
            class1 cls1 = new class1();
            cls1.val = 1;
 
            class1 cls2 = cls1;
 
            Console.WriteLine("cls1.val = " + cls1.val);
            Console.WriteLine("cls2.val = " + cls2.val);
 
            cls2.val = 3;
 
            //After changing data
            Console.WriteLine("cls1.val = " + cls1.val);
            Console.WriteLine("cls2.val = " + cls2.val);
 
            Console.ReadLine();
        }
    }
 
    //created class for use in reference type example
    class class1
    {
        public int val;
    }
}

If you look at the above code we have declared 2 int variables i and j. When I copy data from i to j, separate copy of data for j gets created on stack. in next line i am changing the value of j. when we print this on console, i value doesn't get changed. So this concludes that there is separate copy of data for variable i and j.

In contrast to this, in above code When I declare variable cls1 of type class1(class is reference type), assign value as 1, Memory gets allocated for this cls1 variable on stack which contains reference for address of memory location for data i.e. 1 which gets stored on Heap.
Now when I create another variable of class1 cls2, and copy data of cls1 into it, memory gets allocated for this variable on stack but the it contains same reference of address for memory location for the data to which cls1 pointing i.e. 1. No separate copy of data gets created in this case for cls2 variable.
Now see next line where I assigned new value to cls2 i.e. 3 and I have not made any change in cls1 value. If you check the output, you can see that value for cls1 also gets changed to 3. This is because cls1 and cls2, both pointing to same memory location on Heap.

Value type and Rereference type variable in C#

Data Type And Variables

A variable is nothing but a data store in which we store data that we are going to use in our application and data type is a term which describe what type of data you are storing in that variable.
So in order to store data in a variables, we first have to declare that variable and also declare the type of data we are storing in it i. e. we have to specify the data type for our variables declared.

below is variable declaration syntax and example.

[Data Type name] [variable name]

+
int i;
i = 123;
 
string j;
j = "Testing";

There are various built-in data types available in dot net framework. We can see in our above example 2 data type samples int in which we store only integer values and string in which we can store only string values. We can build our own custom data type as well.
Now Compiler uses this information to make sure that all the operations/assignments that are going to happen in your code are type safe and hence we are saying that C# is strongly typed language. Meaning that we can store only integer values into variable whose data type is int. If we are going to store values other than int, it will gives us error or inconsistent result.
For example if I am going to make addition of above variables i and j and storing it in another int variable k, then compiler will give error Cannot implicitly convert type 'string' to 'int' 

+
int k;
k = i + j;

Below table gives list of Data types present in dot net framework with their Size limit. If we store data beyond the size limit then compiler will give an error.

Data TypeSize
sbyte-128 to 127
byte0 to 255
charU+0000 to U+ffff
short-32,768 to 32,767
ushort0 to 65,535
int-2,147,483,648 to 2,147,483,647
uint0 to 4,294,967,295
long-9,223,372,036,854,775,808 to 9,223,372,036,854,775,807
ulong0 to 18,446,744,073,709,551,615
float±1.5e−45 to ±3.4e38
double±5.0e−324 to ±1.7e308
string0 to approx. two billion (2 ^ 31) Unicode characters

You can check each data type size limit by using MaxValue and MinValue properties of data type. for example if you want to check size of int data type then simply write int.MaxValue for getting maximum value and int.MinValue for minimum value in your code.

Arrays in C#.Net

Array is a collection of similar data types. It is a sequential arrangements of our data and the data is stored with index starting from 0 index. We can use these index to access elements of an array. Arrays can be single dimensional, Multi dimensional or we can have arrays within array.

below is a syntax to declare array and an example of array.

[Data type][] variableName = new [Data type][size of array]

+
using System;
using System.Linq;
 
namespace arrayEx
{
    class Program
    {
        static void Main(string[] args)
        {
            int[] num = {1,2,3,4,5};
            string[] str = { "Ravi""Ramesh""Sidhu" };
 
            Console.WriteLine("***** Printing numbers *****");
            for (int i = 0; i < num.Count(); i++)
            {
                Console.WriteLine(num[i]);
            }
 
            Console.WriteLine("\n***** Printing name *****");
            for (int j = 0; j < str.Count(); j++)
            {
                Console.WriteLine(str[j]);
            }
 
            //replacing element at index 0 with another element
            num[0] = 6;
 
            Console.WriteLine("\n***** Printing numbers *****");
            for (int i = 0; i < num.Count(); i++)
            {
                Console.WriteLine(num[i]);
            }
 
            num[5] = 7;
 
            Console.ReadLine();
        }
    }
}

In the above sample code we declared two single dimensional arrays num and str. num stores integer data and str array stores string data. We have initialised array at the declaration in {} bracket. Whatever Number of items we initialise there, that would be the max size of an array. In above example num array initialised with 5 elements and str array initialised with 3 elements. so this will be the maximum size of our array declared. so later in code we can't add more than 5 and 3 elements for our array num and str respectively. If I am trying to add element at 5th index position( num[5] = 7;) later it will give runtime error of out of index.
We can replace any array element with other element like in above code sample where i replaced element 1 of num array which is at index 0 with 6. You can see printed output with 6 at first position. See below output for our above code.



We can initialise the array size while declaring it and later add elements to this array upto the declared size of an array. See below code sample for the same where array size is declared as 10 at the time of declaration. So we can add max 10 elements for this array starting from index 0 till 9.

+
using System;
using System.Linq;
 
namespace arrayEx
{
    class Program
    {
        static void Main(string[] args)
        {
            int[] num = new int[10];
 
            num[0] = 1;
            num[1] = 2;
            num[2] = 3;
 
            Console.WriteLine("***** Printing numbers *****");
            for (int i = 0; i < num.Count(); i++)
            {
                Console.WriteLine(num[i]);
            }
 
            Console.ReadLine();
        }
    }
}

Below is the output for above code. If you see in above code we added only 3 elements in array. When we print this array, we can see that rest of elements are 0.

Arrays in C#