DotNet - Basics at A Glance
DotNet - Basics at A Glance
DotNet - Basics at A Glance
Access Modifiers:
Access modifiers are keywords added to the class, struct, or member declaration to
specify restrictions, so that only the program or namespace they are declared in may use them.
Types of Access Modifiers:
a. Public
b. Private
c. Internal
d. Protected
e. ProtectedInternal
namespace Exp
{
public class Class1
{
public int a = 0;private int b = 1;protected int c = 2 ;
internal int d = 3;protected internal int e = 4;
}
public class test
{
public void x()
{
Class1 c = new Class1();
c.{a,d,e} //{b,c}private and protected are not accessible
test t = new test();
t. // Nothing is accessible
}
}
}
//////////////////////////////////////////////
namespace Exp
{
public class Class1
{
public int a = 0; private int b = 1;protected int c = 2 ;
internal int d = 3; protected internal int e = 4;
}
public class test:Class1 //if inherited
{
public void x()
{
Class1 c = new Class1();
c.{a,d,e} //private and protected are not accessible
test t = new test();
t.{a,c,d,e} // {b}private is not accessible
}
}
}
/////////////////////////////////////////////////////
using Exp; // adding as reference
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Exp.Class1 c = new Class1();
c.a ;//public alone is accessible
Program p = new Program();
p.//nothing is accessible
}
}
}
////////////////////////////////////////////////////////////
namespace ConsoleApplication1
{
class Program:Class1 //if inherited
{
static void Main(string[] args)
{
Exp.Class1 c = new Class1();
c.a ;//public alone is accessible
Program p = new Program();
p.{a,c,e} //public,protected,protected internal are accessible
//private and internal are not accessible
}
}
}
//////////////////////////////////////////////////////////
Example:
public class First // public class
{
public int x=5; // public variable
}
public class Second
{
static void Main()
{
First f=new First();
f.x = 6; // Can be accessed even without inheriting
}
}
Protected: Accessible to current class and all derived classes even in other application.
Example
}
}
Internal: Accessible to any class in the current assembly or DLL. That is if another program which is
adding main program’s DLL as reference and tries to access its variables or members, only elements
having public access are accessible but not Internal or others
Protected Internal: Protected Internal may be accessed only by a derived class that's contained
in the other application or any class in its same assembly. You use protected internal in situations
where you want to deny access to parts of a class functionality to any descendant classes found
in other applications which does not inherit this class.
Access limited to this program or types derived from the containing class".
Important points to be noted with Access modifiers
2. Individual classes can be either public or internal but not protected or private. So
Private class NewClass {} will produce a compile-time error. By default, classes are
internal. By default, methods and variables in class are private
3. Interfaces, like classes can be either public or internal but not protected or private.
5. Enums are always public. They cannot have access modifiers either.
7. Derived classes can either have the same restriction level or can be more restrictive than the
base class but not less restrictive. So
8. Nested classes can have any access modifier.(classes inside other class)
namespace ConsoleApplication4 {
public class A
{
protected int b = 7;
internal int c = 1;
public int d = 2;
internal class B {
public int x = 3;
int y = 5;
}
protected class C {
public int z = 4;
}
}
class E:A
{
E e = new E();
A a = new A();
void main()
{
//e.{b,c,d } are accessible but not x,y or z
a.c = 5;
a.d = 6;
Keywords:
Method Definitions:
Override example
If override is used, then sealed may also be used to specify that no further modifications can be
made to this method in derived classes, that is, this method can't be overridden by derived
classes.
public class MyDerivedClass : MyBaseClass
{
public override sealed void DoSomething()
{
// Derived class implementation, overrides base implementation.
}
}
namespace ConsoleApplication1
{
public abstract class absClass // This is an abstract class
{
public void nonabsmethod() // nonabstract method which is defined
{
Console.WriteLine("This is Non Abstract Method Definition");
}
public abstract void absmethod (); //method to be defined in derived class
}
interface myinterface
{
void method();
}
interface myinterface2
{
void method2();
}
A constant expression is an expression that can be fully evaluated at compile time. Therefore, the
only possible values for constants of reference types are string and null.
Readonly: The readonly keyword is a modifier that can be used on fields or variables. When a field
declaration includes a readonly modifier, assignments (initialization) to the fields can only occur in
the declaration or in a constructor in the same class.
Ex:
Public readonly int y = 5;
class Dog
{
readonly int x = 5;
readonly int y;
readonly int z;
public Dog() //Constructor
{
y = 6; // Initializing is accepted
}
static void Main()
{
z = 7; // Not possible-causes compile time error
}
}
The readonly keyword is different from the const keyword. A const field can only be initialized at the
declaration of the field. A readonly field can be initialized either at the declaration or in a constructor.
Therefore, readonly fields can have different values depending on the constructor used. Also, while a
const field is a compile-time constant, the readonly field can be used for runtime constants as in the
following example:
public SampleClass()
{
z = 24; // Initialize a readonly instance field
}
Output
p1: x=11, y=21, z=32
p2: x=55, y=25, z=24
Comments
In the preceding example, if you use a statement like this:
p2.y = 66; // Error you will get the compiler error message:
byte destinationVar;
short sourceVar = 281;
destinationVar = unchecked((byte)sourceVar);
Console.WriteLine("sourceVar val: {0}", sourceVar);
Console.WriteLine("destinationVar val: {0}", destinationVar);
Console.ReadKey();
Output:
sourceVar val: 281
destinationVar val: 25
Static: static modifier is used to declare a static member, which belongs to the type itself
rather than to a specific object, which means it cannot be accessed through any other object. The
static modifier can be used with classes, fields, methods, properties, operators, events and
constructors, but cannot be used with indexers, destructors, or types other than classes
Ex:
Public class Base
To refer to the static member x, use the fully qualified name (unless it is accessible from the
same scope):
Base.Structure.x
Static Classes
A class can be declared static, indicating that it contains only static members. It is not possible to
create instances of a static class using the new keyword. Static classes are loaded automatically
by the .NET Framework common language runtime (CLR) when the program or namespace
containing the class is loaded.
Static Members
A static method, field, property, or event is callable on a class even when no instance of the class
has been created. If any instances of the class are created, they cannot be used to access the
static member. Only one copy of static fields and events exists, and static methods and
properties can only access static fields and static events. Static members are often used to
represent data or calculations that do not change in response to object state; for instance, a
math library might contain static methods for calculating sine and cosine.
Static class members are declared using the static keyword before the return type of the
member, for example:
Static members can access only static fields .Whereas non static methods can
access both static and non static fields.
class x
{
public int w = 7;
static int e = 9;
static void method()
{
e = 5;
w = 7; // Not allowed
}
void method2()
{
w = 10;
e = 10;
}
static void Main()
{
}
}
Constructor in C#:
Broadly speaking, it is a method in the class which gets executed when its object is
created. Usually we put the initialization code in the constructor. Constructors cannot have a
return type. Writing a constructor in the class is damn simple, have a look at the following
sample :
When the object of this class is instantiated the constructor will be executed. Something like
this:
mySampleClass obj = new mySampleClass()
// At this time the code in the constructor will be executed
The call to the constructor now depends on the way you instantiate the object. For example:
The call to the constructors is completely governed by the rules of the overloading here.
Calling Constructor from another Constructor: You can always make the call to one
constructor from within the other. Say for example:
public mySampleClass()
{
mySampleClass(10) //or public mySampleClass(): this(10)
// This is the no parameter constructor method.
// First Constructor
}
Here if I instantiate the object as
mySampleClass obj = new mySampleClass ();
Then the code of public mySampleClass (int Age) will be executed before the code of
mySampleClass ().
*Note that only this and base keywords are allowed in initializers, other method calls will raise
the error.
Here the new keyword base has come into picture. This refers to the base class of the current
class. So, here it refers to the myBaseClass. And base(10) refers to the call to myBaseClass(int
Age) method.
Static Constructors:
This is a special constructor and gets called before the first object of the class is created. The
time of execution cannot be determined, but it is definitely before the first object creation - could
be at the time of loading the assembly.
Ok fine, all the above points are fine but why is it like that? Let us go step by step here.
Firstly, the call to the static method is made by the CLR and not by the object, so we do not need
to have the access modifier to it.
Secondly, it is going to be called by CLR, who can pass the parameters to it, if required, No one,
so we cannot have parameterized static constructor.
Thirdly, Non-static members in the class are specific to the object instance so static constructor,
if allowed to work on non-static members, will reflect the changes in all the object instances,
which is impractical. So static constructor can access only static members of the class.
Fourthly, Overloading needs the two methods to be different in terms to methods definition,
which you cannot do with Static Constructors, so you can have at the most one static constructor
in the class.
Now, one question raises here, can we have the two constructors as
3. What if I have the constructor public myDerivedClass () but not the public
myBaseClass ()?
It will raise an error. If either the no parameter constructor is absent or it is in-accessible ( say it
is private ), it will raise an error. You will have to take the precaution here.
It is an error to use the abstract and extern modifiers together to modify the same member.
Using the extern modifier means that the method is implemented outside the C# code, while
using the abstract modifier means that the method implementation is not provided in the class.
1. When a method declaration includes an extern modifier, the method is said to be an external
method.
2 External methods are implemented externally, typically using a language other than C#.
3 Because an external method declaration provides no actual implementation, the method-body
of an external method simply consists of a semicolon.
Ex:
[DllImport ("avifil32.dll")]
Private static extern void AVIFileInit();
Ex:
using System;
using System.Runtime.InteropServices;
class MainClass
{
[DllImport("User32.dll")]
public static extern int MessageBox(int h, string m, string c, int type);
Void:
It specifies a return value type for a method that does not return a value. (i.e.) When used as
the return type for a method, void specifies that the method does not return a value. A method
that takes no parameters and returns no value is declared as follows:
Ex:
Void Method1 ();
Lock:
The lock keyword marks a statement block as a critical section by obtaining the mutual-
exclusion lock for a given object, executing a statement, and then releasing the lock. This
statement takes the following form:
Ex:
Object thisLock = new Object();
lock (thisLock)
{
// Critical code section
}
lock ensures that one thread does not enter a critical section of code while another thread is in
the critical section. If another thread attempts to enter a locked code, it will wait, block, until the
object is released.
lock calls Enter at the beginning of the block and Exit at the end of the block.
In general, avoid locking on a public type, or instances beyond your code's control.
The common constructs lock (this), lock (typeof (MyType)), and lock ("myLock"):
• lock ("myLock") is a problem since any other code in the process using the same string,
will share the same lock.
Best practice is to define a private object to lock on, or a private static object variable to
protect data common to all instances.
Volatile:
The volatile keyword indicates that a field might be modified by multiple concurrently
executing threads. Fields that are declared volatile are not subject to compiler
optimizations that assume access by a single thread. This ensures that the most up-to-date
value is present in the field at all times.
The following example shows how to declare a public field variable as volatile.
// csharp_volatile.cs
Class Test
{
Public volatile int i;
Test (int _i)
{
i = _i;
}
}
Whenever a volatile is requested, the system returns the current value at the time of the request. All
assignments are written to the object immediately.
Common usage of the volatile modifier is when a particular field is accessed by many threads without
using the lock statement to serialize access. So in essence the volatile modifier guarantees that a thread
will retrieve the most recent value written by another thread (even if it was modified by the previous
instruction from you call).
You are not allowed to use volatile on just any type. The following is a list of types you can
implement this modifier on:
The volatile keyword can only be applied to fields of a class or struct. Local variables cannot be
declared volatile.
Sealed:
The sealed modifier can be applied to classes, instance methods and properties. A sealed
class cannot be inherited. A sealed method overrides a method in a base class, but itself cannot
be overridden further in any derived class.
When applied to a method or property, the sealed modifier must always be used with override.
Use the sealed modifier in a class declaration to prevent inheritance of the class
* It is an error to use a sealed class as a base class or Abstract modifier in sealed class.
* Structs are implicitly sealed; therefore, they cannot be inherited.
Ex: Sealed method
class A{
public virtual void First() {
Console.WriteLine("A.F");
}
public virtual void Second() {}
}
class B: A{ //Override keyword used along with sealed modifier in sealed method
sealed override public void First () {
Console.WriteLine("B.F");
}
override public void Second () {
Console.WriteLine("B.G");
}
}
class C: B{
override public void Second () {
Console.WriteLine("C.G");
}
}
Abstract:
The abstract modifier can be used with classes, methods, properties, indexers, and events. Use
the abstract modifier in a class declaration to indicate that a class is intended only to be a base
class of other classes. Members marked as abstract, or included in an abstract class, must be
implemented by classes that derive from the abstract class.
In this example, the class square must provide an implementation of method Area because it derives
from Abstract class Shape:
Ex:
Abstract properties behave like abstract methods, except for the differences in
declaration and invocation syntax.
* It is an error to use the abstract modifier on a static property.
* An abstract inherited property can be overridden in a derived class by including a property
declaration that uses the override modifier.
* An abstract class must provide implementation for all interface members.
* An abstract class that implements an interface might map the interface methods onto abstract
methods.
interface I{
void M();
}
abstract class C : I{
public abstract void M();
}
Interface:
An interface contains only the signatures of methods, delegates or events. The implementation of
the methods is done in the class that implements the interface
Interface ISampleInterface
{
Void SampleMethod ();
}
Class ImplementationClass : ISampleInterface
{
// Explicit interface member implementation:
Void ISampleInterface.SampleMethod ()
{
// Method implementation.
}
Static void Main ()
{
// declare an interface instance.
ISampleInterface obj = new ImplementationClass();
// Call the member.
obj.SampleMethod();
}
}
* An interface can be a member of a namespace or a class and can contain signatures of the
following members: Methods ; Properties ; Indexers; Events
* An interface can inherit from one or more base interfaces.
* When a base type list contains a base class and interfaces, the base class must come first in
the list.
* A class that implements an interface can explicitly implement members of that interface. An
explicitly implemented member cannot be accessed through a class instance, but only through an
instance of the interface.
using System;
interface IPoint{
int x{ // Property signatures:
get;
set;
}
int y{
get;
set;
}
}
class Point : IPoint{
private int _x;// Fields:
private int _y;
public Point(int x, int y){ // Constructor:
_x = x;
_y = y;
}
public int x{ // Property implementation:
get{
return _x;
}
set{
_x = value;
}
}
public int y{
get{
return _y;
}
set{
_y = value;
}
}
}
class MainClass{
static void PrintPoint(IPoint p){
Console.WriteLine("x={0}, y={1}", p.x, p.y);
}
static void Main(){
Point p = new Point(2, 3);
Console.Write("My Point: ");
PrintPoint(p);
}
}
Output
My Point: x=2, y=3
5. All the members of Interface should be Only the members marked as Abstract need
implemented in the derived class to be implemented in the derived class
6. If we add new method to an interface If new methods are added they can be
we need to track down all the inherited implemented in the class itself so no need to
classes and implement these methods implement in inherited classes
Params:
The params keyword lets you specify a method parameter that takes an argument where the
number of arguments is variable.
No additional parameters are permitted after the params keyword in a method declaration, and
only one params keyword is permitted in a method declaration.
Ex:
using System;
public class MyClass{
public static void UseParams(int y,params int[] x) {
for (int i = 0; i < x.Length; i++){
Console.Write (x[i]);
}
Console.Write (y);
}
static void Main(){
UseParams(5,1, 2, 3);
}
}
Output:
1235
Ref & Out Parameters:
Ref:
The ref keyword causes arguments to be passed by reference. The effect is that any
changes made to the parameter in the method will be reflected in that variable when control
passes back to the calling method. To use a ref parameter, both the method definition and the
calling method must explicitly use the ref keyword
Although ref and out are treated differently at run-time, they are treated the same at compile
time. Therefore methods cannot be overloaded if one method takes a ref argument and the other
takes an out argument. These two methods, for example, are identical in terms of compilation,
so this code will not compile
Class Example
{
// compiler error CS0663: "cannot define overloaded
// methods that differ only on ref and out"
Public void Method (ref int I) { }
Public void Method (out int I) { }
}
Overloading can be done, however, if one method takes a ref or out argument and the other
uses neither, like this:
Class RefOutOverloadExample
{
Public void Method (int I) { }
Public void Method (ref int I) { }
}
Ref is also useful for passing reference types. This allows called methods to modify the object to
which the reference refers because the reference itself is being passed by reference. The
following sample shows that when a reference type is passed as a ref parameter, the object itself
can be changed.
Out:
The out keyword causes arguments to be passed by reference. This is similar to the ref
keyword, except that ref requires that the variable be initialized before being passed. To use an
out parameter, both the method definition and the calling method must explicitly use the out
keyword.
Class Example
{
Static void Method (out int I)
{
I = 44; // need to be initialized before method returns
}
Static void Main ()
{
int value;
Method (out value);
// value is now 44
}
}
* Although variables passed as an out arguments need not be initialized prior to being passed,
the called method is required to assign a value before the method returns.
class TestOut
{
static void FillArray(out int[] arr) {
// Initialize the array:
arr = new int[5] { 1, 2, 3, 4, 5 };
}
Output 1
Array elements are: 1 2 3 4 5
In this example, the array theArray is initialized in the caller(the Main method), and passed to
the FillArray method by using the ref parameter. Some of the array elements are updated in the
FillArray method. Then, the array elements are returned to the caller and displayed.
class test
{
static void FillArray(ref int[] arr)
{
// Create the array on demand:
if (arr == null)
{
arr = new int[10];
}
// Fill the array:
arr[0] = 1111;
arr[4] = 5555;
}
static void Main()
{
// Initialize the array:
int[] theArray = { 1, 2, 3, 4, 5 };
Output:
Array elements are: 1111 2 3 4 5555
Unsafe:
The unsafe keyword denotes an unsafe context, which is required for any operation involving
pointers.
The unsafe content will not run under CLR. We have to use Compile with Unsafe option
to run these codes. (Properties_Build –Allow Unsafe Code should be checked)
You can use the unsafe modifier in the declaration of a type or a member. The entire textual
extent of the type or member is therefore considered an unsafe context. For example, the
following is a method declared with the unsafe modifier:
Unsafe static void Copy (byte [] source, byte [] destination, int count)
{
// Unsafe context: can use pointers here.
}
The scope of the unsafe context extends from the parameter list to the end of the method, so
pointers can also be used in the parameter list:
Unsafe static void Copy (byte* ps, byte* Pd, int count)
{...}
We can also use an unsafe block to enable the use of an unsafe code inside this block.
Unsafe
{
// Unsafe context: can use pointers here.
}
* Unsafe code may increase an application's performance by removing array bounds checks.
* Unsafe code is required when calling native functions that require pointers.
* In order for C# to compile unsafe code, the application must be compiled with /unsafe.
Ex:
class UnsafeTest
{
// Unsafe method: takes pointer to int:
unsafe static void SquarePtrParam(int* p)
{
*p = *p * *p; // *p *= *p;
}
unsafe static void Copy(byte* ps, byte* Pd, int count)
{}
New:
In C#, the new keyword can be used as an operator, a modifier, or a constraint.
In the preceding statement, x is initialized to ‘0’, which is the default value for the type int. The
statement has the same effect as the following:
int x=0;
New Modifier: Used to hide an inherited member from a base class member.
When used as a modifier, the new keyword explicitly hides a member inherited from a
base class. Hiding an inherited member means that the derived version of the member replaces
the base-class version. Hiding members without the use of the new modifier is allowed, but
generates a warning. Using new to explicitly hide a member suppresses this warning, and
documents the fact that the derived version is intended as a replacement.
To hide an inherited member, declare it in the derived class using the same name, and modify it
with the new modifier
It is an error to use both new and override on the same member, as the two modifiers have
mutually exclusive meanings.
Using new creates a new member with the same name and causes the original member to
become hidden, while override extends the implementation for an inherited member.
Using the new modifier in a declaration that does not hide an inherited member generates a
warning.
Output : 100 55 22
In the above example, a base class, BaseC, and a derived class, DerivedC, use the same field
name x, thus hiding the value of the inherited field.. It also demonstrates how to access the
hidden members of the base class by using their fully qualified names
New Constraint: Used to restrict types that might be used as arguments for a type parameter in a
generic declaration.
The new constraint specifies that any type argument in a generic class declaration must have a
public parameter less constructor. Apply this constraint to a type parameter when your generic
class creates new instances of the type, as shown in the following example:
When you use the new () constraint with other constraints, it must be specified last:
class ItemFactory<T> where T : IComparable, new() {}
Base:
The base keyword is used to access members of the base class from within a derived class.
* Call a method on the base class that has been overridden by another method.
* Specify which base-class constructor should be called when creating instances of the derived class.
* A base class access is permitted only in a constructor, an instance method, or an instance property
accessor.
* It is an error to use the base keyword from within a static method.
In this example, both the base class Person, and the derived class Employee, have a method
named GetInfo. By using the base keyword, it is possible to call the GetInfo method on the base
class, from within the derived class.
Ex:
class TestClass
{
static void Main(){
Employee E = new Employee();
E.GetInfo();
}
}
Output:
Name:John L. Malgraine
SSN : 444-55-6666
Employee ID: ABC567EFG
This example shows how to specify the base-class constructor called when creating instances of a
derived class.
using System;
public class BaseClass
{
int num;
public BaseClass(){
Console.WriteLine("in BaseClass()");
}
public BaseClass(int i){
num = i;
Console.WriteLine("in BaseClass(int i)");
}
public int GetNum() {
return num;
}
}
public class DerivedClass : BaseClass
{
// This constructor will call BaseClass.BaseClass()
public DerivedClass(): base()
{
}
// This constructor will call BaseClass.BaseClass(int i)
public DerivedClass(int i): base(i)
{
}
static void Main() {
DerivedClass md = new DerivedClass();
DerivedClass md1 = new DerivedClass(1);
}
}
Output:
in BaseClass()
in BaseClass(int i)
This:
The this keyword refers to the current instance of the class.
this.name = name;
this.alias = alias;
CalcTax (this);
* Static member functions do not have this pointer because they exist at the class level and not
as part of an object. It is an error to refer to this in a static method
In this example, this is used to qualify the Employee class members, name and alias, which are
hidden by similar names. It is also used to pass an object to the method CalcTax, which belongs
to another class
Ex:
using System;
class Employee
{
private string name;
private string alias;
private decimal salary = 3000.00m;
public Employee()
{
this.name = "xxx"; // Use this to qualify the fields, name and alias:
this.alias = "yyy";
}
// Constructor:
public Employee(string name, string alias) {
this.name = name; // Use this to qualify the fields, name and alias:
this.alias = alias;
}
public void printEmployee() { // Printing method:
Console.WriteLine("Name: {0}\nAlias: {1}", name, alias);
// Passing the object to the CalcTax method by using this:
Console.WriteLine("Taxes: {0:C}", Tax.CalcTax(this));
}
public decimal Salary {
get { return salary; }
}
}
class Tax
{
public static decimal CalcTax(Employee E) {
return 0.08m * E.Salary;
}
}
class MainClass
{
static void Main() {
// Create objects:
Employee E0 = new Employee();
E0.printEmployee();
Employee E1 = new Employee("John M. Trainer", "jtrainer");
// Display results:
E1.printEmployee();
Console.ReadKey();
}
}
Output:
Name: xxx
Alias: yyy
Taxes: $240.00
Name: John M. Trainer
Alias: jtrainer
Taxes: $240.00
Properties:
Properties are members that provide a flexible mechanism to read, write, or compute
the values of private fields. Properties can be used as though they are public data members, but
they are actually special methods called accessors. This enables data to be accessed easily while
still providing the safety and flexibility of methods.
The code block for the get accessor is executed when the property is read; the code block for the
set accessor is executed when the property is assigned a new value. A property without a set
accessor is considered read-only. A property without a get accessor is considered write-only. A
property with both accessors is read-write.
Ex:
The above class has one private field - color. Then we have one "Property" called “PropColor”,
which is used to represent the private field. Note that the field is private and the Property is
public.
When executed, the above get accessor will return the value stored in the field 'color'.
The set part is executed when you assign a value to the Property as shown below:
When executed, the above set accessor will assign the value "RED" to the private field 'color'. (Note
that 'value' is a keyword, which will have the value assigned to it.)
Let us analyze the get part first. Here we are checking whether there is a valid value in the field 'color'
before we return the value. If it is empty, we are getting a chance to return a default value 'Green'. This
way, we can make sure that whoever calls the property ‘Color’ will always gets a valid color, never an
empty string.
In the set part, we are doing a validation to make sure we always assign a valid value to our field. If
someone assigns an empty string to the 'Color' property, he will get an exception (error).
Indexer:
Indexers permit instances of a class or struct to be indexed in the same way as arrays.
Indexers are similar to properties except that their accessors take parameters.
Declaration:
using System;
using System.Collections;
class MyClass
{
private string[] data = new string[5];
public string this[int index]{
get {
return data[index];
}
set {
data[index] = value;
}
}
}
class MyClient
{
public static void Main() {
MyClass mc = new MyClass();
mc[0] = "Rajesh";
mc[1] = "Ponmalai";
mc[2] = "Trichy";
mc[3] = "TamilNadu";
mc[4] = "India";
Console.WriteLine("{0},{1},{2},{3},{4}", mc[0], mc[1], mc[2], mc[3], mc[4]);
Console.ReadKey();
}
}
Output: Rajesh, Ponmalai, Trichy, TamilNadu, India.
StringBuilder:
The class StringBuilder, in namespace System.Text which provides us with a dynamic string
builder class. Normally if we have used the string data type it will create a new string object each
time we modify the string, and refer to that new object. This can harm the performance of the
application, but the class StringBuilder supports string modifications without creating a new
object.
Partial Class:
It is possible to split the definition of a class or a struct, or an interface (not available in
Delegate or Enumeration) over two or more source files. Each source file contains a section of the
class definition, and all parts are combined when the application is compiled. There are several
situations when splitting a class definition is desirable:
When working on large projects, spreading a class over separate files allows multiple
programmers to work on it simultaneously.
When working with automatically generated source, code can be added to the class without having to
recreate the source file. Visual Studio uses this approach when creating Windows Forms, Web
Service wrapper code, and so on. You can create code that uses these classes without having to edit
the file created by Visual Studio.
Using the partial keyword indicates that other parts of the class, struct, or interface can be defined
within the namespace. All the parts must use the partial keyword. All of the parts must be available
at compile time to form the final type. All the parts must have the same accessibility, such as public,
private, and so on.
If any of the parts are declared abstract, then the entire type is considered abstract. If any of the
parts are declared sealed, then the entire type is considered sealed. If any of the parts declare a
base type, then the entire type inherits that class.
All partial-type definitions meant to be parts of the same type must be defined in the same
assembly and the same module (.exe or .dll file). Partial definitions cannot span multiple modules
class Container {
partial class Nested {
Void Test () { }
}
partial class Nested {
Void Test2 () { }
}
}
At compile time, attributes of partial-type definitions are merged. the following declarations:
[System.SerializableAttribute]
partial class Moon { }
[System.ObsoleteAttribute]
partial class Moon { } // are equivalent to:
[System.SerializableAttribute]
[System.ObsoleteAttribute]
class Moon { }
Example:
public partial class CoOrds {
private int x; private int y;
public CoOrds(int x, int y){
this.x = x;
this.y = y;
}
}
public partial class CoOrds {
public void PrintCoOrds(){
System.Console.WriteLine("CoOrds: {0},{1}", x, y);
}
}
class TestCoOrds {
static void Main(){
CoOrds myCoOrds = new CoOrds(10, 15);
myCoOrds.PrintCoOrds();
}
} Output : CoOrds: 10, 15
Break:
The break statement terminates the closest enclosing loop or switch statement in which it
appears. Control is passed to the statement that follows the terminated statement, if any.
In this example, the conditional statement contains a counter that is supposed to count from 1 to
100; however, the break statement terminates the loop after 4 counts.
class BreakTest {
static void Main() {
for (int i = 1; i <= 100; i++){
if (i == 5) {
break;
}
Console.Write(i);
}
}
}
Output: 1 2 3 4
Switch:
The switch statement is a control statement that handles multiple selections and enumerations
by passing control to one of the case statements within its body.
* Control is transferred to the case statement which matches the value of the switch.
* Execution of the statement body begins at the selected statement and proceeds until the break
statement transfers control out of the case body.
* A jump statement such as a break is required after each case block, including the last block
whether it is a case statement or a default statement.
* With one exception, C# does not support an implicit fall through from one case label to
another. The one exception is if a case statement has no code.
* If no case expression matches the switch value, then control is transferred to the statement(s)
that follow the optional default label. If there is no default label, control is transferred outside
the switch.
// n should be defined earlier as int and according to value in n it will be searched in case
switch (n) // n = 1 or 2 or 3
{
case 1:
case 2:
case 3:
Console.WriteLine("It's 1, 2, or 3.");
break;
default:
Console.WriteLine("Not sure what it is.");
break;
}
Output : It's 1, 2, or 3.
}
Output : Not sure what it is.
Enum:
Enum is a complex type of variable which can take one of a fixed set of results.
Defining Enumerations
Enumerations can be defined using the enum keyword as follows:
enum typeName: Underlying type
{
value1,
value2,
value3,
...
valueN
}
Next, you can declare variables of this new type with
typeName varName;
and assign values using:
VarName = typeName.value;
Example
namespace ConsoleApplication1 {
enum orientation :int { //int is the underlying type which can be assigned
// byte, sbyte, short, ushort, int, uint, long, or ulong are allowed
north=20 ,
south=30,
east=4 ,
west
} //float or string are not allowed to store in enum
class Program {
static void Main(string[] args) {
orientation myDirection = orientation.north;
Console.WriteLine("myDirection = {0}",myDirection);
orientation myDirection1 = orientation.north;
Console.WriteLine("myDirection = {0}", (byte)myDirection1);
orientation myDirection2 = orientation.east;
Console.WriteLine("myDirection = {0}", (byte)myDirection2);
orientation myDirection3 = orientation.west;
Console.WriteLine("myDirection = {0}", (byte)myDirection3);
Console.ReadKey();
}
}
} Output:
myDirection = north ; myDirection = 20 ;myDirection = 4
myDirection = 5
Struct:
A struct type is a value type that is typically used to encapsulate small groups of related variables.
Structs are defined using the struct keyword, for example:
* Structs share almost all the same syntax as classes but it is more limited than classes.
* In struct declaration, fields cannot be initialized unless they are declared as const or static.
* Structs can also contain constructors, constants, fields, methods, properties, indexers,
operators, events, and nested types, although if several such members are required, it is better
to make it as a class instead.
* A class variable can be assigned null. But we cannot assign null to a struct variable, since
structs are value type.
* When a class is instantiated, it will be allocated on the heap. When you instantiate a struct, it
gets created on the stack.
* Structs can implement an interface but they cannot inherit from another struct. For that
reason, struct members cannot be declared as protected.
Structs are value types — when an object is created for a struct and assigned to a variable, the
variable contains the entire value of the struct. When a variable containing a struct is copied, all
of the data is copied, and any modification to the new copy does not change the data for the old
copy.
Structs Overview
* Unlike classes, structs can be instantiated without using a new operator. If you do not use
new, the fields will remain unassigned and the object cannot be used until all of the fields are
initialized
* A struct cannot inherit from another struct or class, and it cannot be the base of a class. All
structs inherit directly from System.ValueType, which inherits from System.Object.
Ex:
namespace ConsoleApplication1 {
enum orientation : byte {
north = 1,
south = 2,
east = 3,
west = 4
}
struct route {
public orientation direction;
public double distance;
}
class Program {
static void Main(string[] args) {
route myRoute;
int myDirection = -1;
double myDistance;
Console.WriteLine("1) North\n2) South\n3) East\n4) West");
do {
Console.WriteLine("Select a direction:");
myDirection = Convert.ToInt32(Console.ReadLine());
}
while ((myDirection < 1) || (myDirection > 4));
Console.WriteLine("Input a distance:");
myDistance = Convert.ToDouble(Console.ReadLine());
myRoute.direction = (orientation)myDirection;
myRoute.distance = myDistance;
Console.WriteLine("myRoute specifies a direction of {0} and a " +
"distance of {1}", myRoute.direction, myRoute.distance);
Console.ReadKey();
}
}
}
Ex:
class TestCoOrds
{
static void Main() {
// Initialize:
CoOrds coords1 = new CoOrds();
CoOrds coords2 = new CoOrds(10, 10);
// Display results:
System.Console.Write("CoOrds 1: ");
System.Console.WriteLine("x = {0}, y = {1}", coords1.x, coords1.y);
System.Console.Write("CoOrds 2: ");
System.Console.WriteLine("x = {0}, y = {1}", coords2.x, coords2.y);
}
}
Output: coOrds 1: x = 0, y = 0 ; coOrds 2: x = 10, y = 10
// Initialize:
coords1.x = 10;
coords1.y = 20;
// Display results:
System.Console.Write("CoOrds 1: ");
System.Console.WriteLine("x = {0}, y = {1}", coords1.x, coords1.y);
}
}
Output: coords 1: x = 10, y = 20
This following shows that when a struct is passed to a method, a copy of the struct is passed, but
when a class instance is passed, a reference is passed.
The output of the following example shows that only the value of the class field is changed when
the class instance is passed to the ClassTaker method. The struct field, however, does not change
by passing its instance to the StructTaker method. This is because a copy of the struct is passed
to the StructTaker method, while a reference to the class is passed to the ClassTaker method.
using System;
class TheClass {
public string willIChange;
}
struct TheStruct {
public string willIChange;
}
class TestClassAndStruct {
static void ClassTaker(TheClass c) {
c.willIChange = "Changed";
}
static void StructTaker(TheStruct s) {
s.willIChange = "Changed";
}
static void Main() {
TheClass testClass = new TheClass();
TheStruct testStruct = new TheStruct();
ClassTaker(testClass);
StructTaker(testStruct);
Array:
Arrays are indexed lists of variables stored in a single array type variable. Arrays have a
single base type, that is, individual entries in an array are all of the same type.
Declaring Arrays
Arrays are declared in the following way:
<baseType>[] <name>;
Ex:
int[] myIntArray = new int[5]; //or
int[] myIntArray = { 5, 9, 10, 2, 99 };
string[] strarray ={ "Hi", "How", "Are", "You" };
int[] myIntArray = new int[5] { 5, 9, 10, 2, 99 };
int[] myIntArray = new int[10] { 5, 9, 10};//Error size and content does not match
int[] myIntArray = new int[arraySize];//arraysize is a variable but that variable
should be constant (constant int arraySize =5;)
Ex:
string[] friendNames = {"Robert Barwell", "Mike Parry","Jeremy Beacock"};
int i;
Console.WriteLine("Here are {0} of my friends:", friendNames.Length);
for (i = 0; i < friendNames.Length; i++) {
Console.WriteLine(friendNames[i]); // accessing array content
}
Console.ReadKey();
Foreach:
A foreach loop allows you to address each element in an array using this simple syntax: Foreach
loop is read only.
String Manipulation:
string myString = "A string";
char myChar = myString[1]; //String can be considered as Char array
string myString = "A string"; //To assign a value should be coverted to char array
char[] myChars = myString.ToCharArray();
int a = myString.Length; // a = 8
string b = myString.ToLower(); // b = a string
string c = myString.ToUpper(); // c = A STRING
string d = myString.Trim(); // if “ A String “ then d = “A String”
string e = myString.TrimStart(); // if “ A String “ then d = “A String ”
string f = myString.TrimEnd(); // if “ A String “ then d = “ A String”
string g= myString.Substring(4); // b = ring ,starts with 0 index
string h = myString.Substring(3,2);// b = tr
int i = 123;
object o = (object)i; // boxing
o = 123;
i = (int)o; // unboxing
Performance:
In relation to simple assignments, boxing and unboxing are computationally expensive processes.
When a value type is boxed, an entirely new object must be allocated and constructed. To a
lesser degree, the cast required for unboxing is also expensive computationally as it needs to
check if the boxed variable is not null or the types are equal.
Command-Line Arguments:
Arguments provided to an executable on the command-line are called Command-Line
Arguments. These are accessible through an optional parameter to Main. The arguments are
provided in the form of an array of strings. Each element of the array contains one argument.
White-space between arguments is removed.
The Main method can use arguments, in which case, it takes one of the following forms:
Ex:
namespace ConsoleApplication6 {
class CommandLine {
static void Main(string[] args) {
// The Length property provides the number of array elements
System.Console.WriteLine("parameter count = {0}", args.Length);
parameter count =5
The Type of the clone is the same as the type of the original Object.
Collection Classes:
The .NET Framework provides specialized classes for data storage and retrieval. These
classes provide support for stacks, queues, lists, and hash tables. Most collection classes
implement the same interfaces, and these interfaces may be inherited to create new collection
classes that fit more specialized data storage needs.
* Most collection classes derive from the interfaces ICollection, IComparer, IEnumerable,
IList, IDictionary, and IDictionaryEnumerator and their generic equivalents.
* Using generic collection classes provides increased type-safety and in some cases can provide
better performance, especially when storing value types
There are a number of interfaces in the System.Collections namespace that provide basic
collection functionality:
The System.Array class implements IList, ICollection, and IEnumerable, but doesn't support some
of the more advanced features of IList, and represents a list of items with a fixed size.
Class Description
Interface Description
IHashCodeProvider Supplies a hash code for an object, using a custom hash function.
Structure Description
Queue: ( System.Collections )
Queue is a Simple DataStucture which allows Insert/Remove of Items at one of the ends only. It is
basically called as FIFO (First In First Out) data structure. i.e. the item which is added first is the first
one to be removed. .NET has a built in class for Queue. It is found in System.Collections namespace.
Any type of objects can be stored in Queue and the Queue capacity increases as per its growth
factor (default 2) if the limit is reached and further elements are added.
Peek() Method : Used to view the Top most object without removing it from Queue
object o=q.Peek(); // o = hi
GetEnumerator() Method : Used to view all the objects without removing it from Queue
Enumerators can be used to read the data in the collection, but they cannot be used to
modify the underlying collection. Initially, the enumerator is positioned before the first element in
the collection. At this position, Current is undefined. Therefore, you must call MoveNext to
advance the enumerator to the first element of the collection before reading the value of Current
An enumerator remains valid as long as the collection remains unchanged. If changes are made
to the collection, such as adding, modifying, or deleting elements, the enumerator is
irrecoverably invalidated and its behavior is undefined. The enumerator does not have exclusive
access to the collection; therefore, enumerating through a collection is intrinsically not a thread-
safe procedure. To guarantee thread safety during enumeration, you can lock the collection
during the entire enumeration. To allow the collection to be accessed by multiple threads for
reading and writing, you must implement your own synchronization.
Stack:
Stack is a Simple DataStucture which allows Insert/Remove of Items at one end (same
end). It is basically called as LIFO (Last In First Out) data structure (i.e. the item which is added
last is the first one to be removed)
Common functions
• Push (): Adds a new object to the last position of the stack.
• Pop (): Returns and removes the last object of the stack.
• Peek (): Returns the last object without removing it.
• IsEmpty (): Validates if the stack is empty.
Ex:
s.Peek(); // To get the Top most element (finally inserted) without removing it.
Output : Work
s.Pop(); // To remove the Top most element (finally inserted element)from stack.
Output : Work
ArrayList:
An ArrayList is an array that can dynamically grow and shrink.It Implements the IList interface to
achieve this property.
Properties:
Capacity - Gets or sets the number of elements that the ArrayList can contain.
Count - Gets the number of elements contained in an ArrayList object.
IsFixedSize - Gets a value indicating whether a ArrayList object has a fixed size. A collection
with a fixed size does not allow the addition or removal of elements after the collection is
created, but does allow the modification of existing elements.
Item - Gets or sets the element at the specified index.
Ex:
Console.WriteLine("Adding 6 elements");
// Add elements to the array list
myArraylist.Add('C');
myArraylist.Add('A');
myArraylist.Add('E');
myArraylist.Add('B');
myArraylist.Add('D');
myArraylist.Add('F');
Output:
Current capacity : 6
Number of elements : 6
Output:
C A E B D F
Output:
A B C D E F
Console.WriteLine("Removing 2 elements");
// Remove elements from the array list.
myArraylist.Remove('C');
myArraylist.Remove('B');
Console.WriteLine("Current capacity: " + myArraylist.Capacity);
Console.WriteLine("Number of elements: " + myArraylist.Count);
Output:
Current capacity : 8
Number of elements : 4
Output:
A D E F
Output:
Current capacity : 16
Number of elements : 14
A D E F a b c d e f g h i j
Console.ReadLine();
}
ArrayList.FixedSize Method:
(If edited or deleted in fixed arraylist, it’s reflected in parent arraylist)
Output:
Initially,
Standard : The quick brown fox
Fixed size: The quick brown fox
After Sort,
Standard : brown fox quick The
Fixed size: brown fox quick The
After Reverse,
Standard : The quick fox brown
Fixed size: The quick fox brown
After adding to the standard ArrayList,
Standard : The quick fox brown AddMe
Fixed size: The quick fox brown AddMe
Hashtable:
Represents a collection of key/value pairs that are organized based on the hash code of the key.
A key cannot be a null reference but should be a value.
Initializing Hashtable:
Create a Hashtable
Hashtable myHashTable = new Hashtable();
Add some data in it.
myHashTable.Add("Key1", "Value1");
myHashTable.Add("Key2", "Value2");
Get the size.
myHashTable.Count; // an int value.
Now to fetch data
Create an object of IDictionaryEnumerator, this is an interface that creates an enumerator
and customized for Dictionary objects.
if (myHashTable.ContainsKey("Key1")) {
Console.WriteLine("Key1 is present");
}
Search for a specific key: remember its value type when used
if (myHashTable.ContainsValue("Value1")) {
Console.WriteLine("Value1 is present");
}
Using Key to get Value:
Output: y=111
When to Use Generic Collections:
Using generic collections is generally recommended, because you gain the immediate benefit of
type safety without having to derive from a base collection type and implement type-specific
members. In addition, generic collection types generally perform better than the corresponding
nongeneric collection types (and better than types derived from nongeneric base collection types)
when the collection elements are value types, because with generics there is no need to box the
elements.
* The Queue, Stack, and SortedList generic classes correspond to the respective nongeneric
classes with the same names.
Additional Types
There are several generic collection types that do not have nongeneric counterparts:
* LinkedList is a general-purpose linked list that provides O(1) insertion and removal operations.
* SortedDictionary is a sorted dictionary with O(log n) insertion and retrieval operations, making
it a useful alternative to SortedList.
* KeyedCollection is a hybrid between a list and a dictionary, which provides a way to store
objects that contain their own keys.
Additional Functionality
Some of the generic types have functionality not found in the nongeneric collection types. For
example, the List class, which corresponds to the nongeneric ArrayList class, has a number of
methods that accept generic delegates, such as the Predicate delegate that allows you to specify
methods for searching the list, the Action delegate that represents methods that act on each
element of the list, and the Converter delegate that lets you define conversions between types.
The List class allows you to specify your own IComparer generic interface implementations for
sorting and searching the list. The SortedDictionary and SortedList classes also have this
capability, and in addition allow the comparers to be specified when the collection is created. In
similar fashion, the Dictionary and KeyedCollection classes allow you to specify your own
equality comparers
** Do you need a sequential list where the element is typically discarded after its value is
retrieved?
If yes, consider using the Queue class or the Queue generic class if you need first-in-first-out
(FIFO) behavior. Consider using the Stack class or the Stack generic class if you need last-in-
first-out (LIFO) behavior. If not, consider using the other collections.
** Do you need to access the elements in a certain order, such as FIFO, LIFO, or random?
The Queue class and the Queue generic class offer FIFO access.
The Stack class and the Stack generic class offer LIFO access.
The LinkedList generic class allows sequential access either from head to Tail or from Tail to
Head.
The ArrayList and StringCollection classes and the List generic class offer access to their
elements by the zero-based index of the element.
The Hashtable, SortedList, ListDictionary, and StringDictionary classes, and the Dictionary and
SortedDictionary generic classes offer access to their elements by the key of the element.
** Will each element contain one value, a combination of one key and one value, or a
combination of one key and multiple values?
One value: Use any of the collections based on the IList interface or the IList generic interface.
One key and one value: Use any of the collections based on the IDictionary interface or the
IDictionary generic interface.
One value with embedded key: Use the KeyedCollection generic class.
** Do you need to sort the elements differently from how they were entered?
The SortedList class and the SortedDictionary and SortedList generic classes sort their
elements by the key, based on implementations of the IComparer interface and the IComparer
generic interface.
ListDictionary is faster than Hashtable for small collections (10 items or fewer). The
SortedDictionary generic class provides faster lookup than the Dictionary generic class.
In addition, you can use any of the generic collection classes in the System.Collections.Generic
namespace as strongly typed string collections by specifying the String class for their generic
type arguments.
Generics:
Generics in C# used to create Type Safe collection.
using System;
using System.Collections.Generic;
namespace GenClass
{
public class GenClass<T>
{
T t;
public T Val
{
get { return t; }
set { t = value;}
}
}
public class GenClassMain
{
public static void Main()
{
//create a string version of our generic class
GenClass<string> mystring = new GenClass<string>();
//set the value
mystring.Val = "hello";
using System;
using System.Collections.Generic;
namespace GenericList
{
public class Person
{
private string name;
private int age;
public string Name
{
get{return name;}
set{name = value;}
}
public int Age
{
get{return age;}
set{age = value;}
}
public static void Main()
{
// now create a collection using the new Generic List
List<Person> employees = new List<Person>();
//now add a couple of generic person objects to the generic collection
Person p1 = new Person();
p1.Name = "John";
p1.Age = 23;
employees.Add(p1);
The result of this is that innerT1Object is assigned a value of null if it is a reference type or a default
value if it is a value type. This default value is 0 for numeric types, while structs have each of their
members initialized to 0 or null in the same way.
Because FileStream is a specific object type, the instance assigned to FS is early bound.
Late binding: Properties and method can be identified by Run time. An object is late bound
when it is assigned to a variable declared to be of type Object. Objects of this type can hold
references to any object, but lack many of the advantages of early-bound objects.
For example, the following code fragment declares an object variable to hold an object returned
by the CreateObject function:
void TestLateBinding()
{
object xlApp;
object xlBook;
object xlSheet;
xlApp = CreateObject("Excel.Application");
xlBook = xlApp.Workbooks.Add;
xlSheet = xlBook.Worksheets(1);
xlSheet.Activate();
xlSheet.Application.Visible = true;
xlSheet.Cells(2, 2) = "This is column B row 2";
}
* Early Binding they allow the compiler to make important optimizations that yield more efficient
applications.
* Early-bound objects are significantly faster than late-bound objects and make your code easier
to read and maintain by stating exactly what kind of objects are being used.
* Another advantage to early binding is that it enables useful features such as automatic code
completion and Dynamic Help because the Visual Studio integrated development environment
(IDE) can determine exactly what type of object you are working with as you edit the code.
* Early binding reduces the number and severity of run-time errors because it allows the
compiler to report errors when a program is compiled.
Advantages of Late Binding:
* The main advantage is that code which uses late binding is more certain to be version-
independent
* The more references your project contains, the larger the file size and the longer it takes to
compile.
* Some programming environments don't allow you to create references to another application.
TypeOf:
You can use the "typeof" operator to obtain information about a type.
The typeof operator returns a System.Type object for a given type.
The typeof operator has this general form: typeof(type)
type is the type being obtained.
The System.Type object returned encapsulates the information associated with type.
Serialization:
Serialization is a process of taking an object and converting into a form so that it can be
transported across the network or can be persisted in the storage location. This storage location
can be physical file, database or ASP.NET Cache. The form contains the state of the object so
that by this format, we can construct the same object a later point in time, which is called
Deserialization.
Example:
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Serialization;
namespace ObjectStore
{
[Serializable]
public class Product
{
public long Id;
public string Name;
public double Price;
[NonSerialized]
string Notes;
public Product(long id, string name, double price, string notes) {
Id = id;
Name = name;
Price = price;
Notes = notes;
}
public override string ToString() {
return string.Format("{0}: {1} (${2:F2}) {3}", Id, Name, Price, Notes);
}
}
public class Program {
static void Main(string[] args){
try
{ // Create products.
List<Product> products = new List<Product>();
products.Add(new Product(1, "Spiky Pung", 1000.0, "Good stuff."));
products.Add(new Product(2, "Gloop Galloop Soup", 25.0, "Tasty."));
products.Add(new Product(4, "Hat Sauce", 12.0, "One for the kids."));
Console.WriteLine("Products to save:");
foreach (Product product in products) {
Console.WriteLine(product);
}
Console.WriteLine();
// Deserialize products.
FileStream loadFile = new FileStream("Products.bin", FileMode.Open);
List<Product> savedProducts =
serializer.Deserialize(loadFile) as List<Product>;
loadFile.Close();
Console.WriteLine("Products loaded:");
foreach (Product product in savedProducts) {
Console.WriteLine(product);
}
}
catch (SerializationException e){
Console.WriteLine("A serialization exception has been thrown!");
Console.WriteLine(e.Message);
}
catch (IOException e) {
Console.WriteLine("An IO exception has been thrown!");
Console.WriteLine(e.ToString());
}
Console.ReadKey();
}
}
}
Though this is the easiest way but at time you need the way so that you can decide what fields to
serialize and how the serialization actually occurs. You can implement the ISerializable interface
in the class. You need two things for that
One of the important parameters is the SerializationInfo object. This object holds a name-value
pair for the properties to be serialized. You can decide which property should be serialized and
which not in the GetObjectData () function. All the properties that are added to this
SerializationInfo parameter will be serialized. Here are the codes for the two functions. Add them
to our Employee class.
Example:
using System;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
namespace MyObjSerial
{
[Serializable()]//Set this attribute to all the classes that want to serialize
public class Employee : ISerializable //derive your class from ISerializable
{
public int EmpId;
public string EmpName;
//Deserialization constructor.
public Employee(SerializationInfo info, StreamingContext ctxt)
{
//Get the values from info and assign them to the appropriate properties
EmpId = (int)info.GetValue("EmployeeId", typeof(int));
EmpName = (String)info.GetValue("EmployeeName", typeof(string));
}
//Serialization function.
public void GetObjectData(SerializationInfo info, StreamingContext ctxt)
{
//You can use any custom name for your name-value pair.
//But make sure you read the values with the same name.If you write EmpId
as "EmployeeId" then you should read the same with "EmployeeId"
info.AddValue("EmployeeId", EmpId);
info.AddValue("EmployeeName", EmpName);
}
}
//Serialization
// Open a file and serialize the object into it in binary format.
// EmployeeInfo.osl is the file that we are creating.
// Note:- you can give any extension you want for your file
Stream stream = File.Open("EmployeeInfo.xxx", FileMode.Create);
BinaryFormatter bformatter = new BinaryFormatter();
//Deserialization
mp = null; //Clear mp for further usage.
//Open the file written above and read values from it.
stream = File.Open("EmployeeInfo.xxx", FileMode.Open);
bformatter = new BinaryFormatter();
What is an assembly?
The assembly which is used only by a single application is called as private assembly. Suppose
you created a DLL which encapsulates your business logic. This DLL will be used by your client
application only and not by any other application. In order to run the application properly your
DLL must reside in the same folder in which the client application is installed. Thus the assembly
is private to your application.
Suppose that you are creating a general purpose DLL which provides functionality which will be
used by variety of applications. Now, instead of each client application having its own copy of DLL
you can place the DLL in 'global assembly cache'. Such assemblies are called as shared
assemblies.
Global assembly cache is nothing but a special disk folder where all the shared assemblies will be
kept. It is located under <drive>:\WinNT\Assembly folder.
As stated earlier most of the assemblies are private. Hence each client application refers
assemblies from its own installation folder. So, even though there are multiple versions of same
assembly they will not conflict with each other. Consider following example:
Now consider the case when you develop assembly that is shared one. In this case it is important
to know how assemblies are versioned. All assemblies have a version number in the form:
major.minor.build.revision
If you change the original assembly the changed version will be considered compatible with
existing one if the major and minor versions of both the assemblies match.
When the client application requests assembly the requested version number is matched against
available versions and the version matching major and minor version numbers and having latest
build and revision numbers are supplied.
How do I create shared assemblies?
Microsoft now uses a public-private key pair to uniquely identify an assembly. These keys are
generated using a utility called SN.exe (SN stands for shared name). The most common syntax of
is :
sn -k mykeyfile.snk
Where k represents that we want to generate a key and the file name followed is the file in which
the keys will be stored.
Before placing the assembly into shared cache you need to sign it using the keys we just
generated. You mention the signing information in a special file called AssemblyInfo. Open the
file from VS.NET solution explorer and change it to include following lines :
[assembly:AssemblyKeyFile("file_path")]
Now recompile the project and the assembly will be signed for you.
Note : You can also supply the key file information during command line compilation via
/a.keyfile switch.
Microsoft has provided a utility called gacutil.exe to actually place your assembly in shared cache.
gacutil /i:my_dll.dll
Hands On...
Now, that we have understood the basics of assemblies let us apply our knowledge by developing
a simple shared assembly.
In this example we will create a VB.NET component called SampleGAC (GAC stands for Global
Assembly Cache). We will also create a key file named sample.key. We will sign our component
with this key file and place it in Global Assembly Cache.
• Step 1 : Creating our sample component
Here is the code for the component. It just includes one method which returns a string.
Imports system
namespace BAJComponents
public class Sample
public function GetData () as string
return "hello world"
end function
end class
end namespace
sn -k sample.key
Now, we will sign the assembly with the key file we just created.
We will use gacutil utility to place the assembly in Global Assembly Cache.
After hosting the assemblies just go to WINNT\Assembly folder and you will find your assembly
listed there. Note how the assembly folder is treated differently that normal folders.
Create a separate folder and copy this assembly in that folder. Then open Machine config file in
the path C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\CONFIG and add the assembly in
that file .Then this dll will be accessible for add reference. On adding even though it shows as if
the path is local folder, its adds the file from GAC while runtime.
Now, we will create a sample client application which uses our shared assembly. Just create a
sample code as listed below:
Imports system
Imports BAJComponents
public class SampleTest
shared sub main ()
dim x as new sample
dim s as string="x".getdata ()
console.writeline(s)
end sub
end class
Now, copy the resulting EXE in any other folder and run it. It will display "Hello World" indicating
that it is using our shared assembly.
Pickling:
When the file is compiled, any attributes defined for assembly in Assemblyinfo.cs file are saved
into the resulting assembly — this process is known as pickling.
Delegates:
* A delegate is a type that enables you to store references to functions.
* Delegates are declared like functions, without function body and using the delegate keyword
* The delegate declaration specifies a function signature consisting of a return type and the
parameter list.
* After defining a delegate, we can declare a variable with the type of that delegate. We can then
initialize this variable as a reference to any function that has the same signature as that of
delegate. Then we call that function by using the delegate variable as if it were a function.
* We can pass a delegate variable to a function as a parameter, then that function can use the
delegate to call whatever function it refers to, without having knowledge as to what function will
be called until runtime.
Ex:
class Program
{
delegate int mydelegate(int x, int y);
Throw:
The throw statement is used to signal the occurrence of an anomalous situation
(exception) during the program execution. Usually the throw statements are used with try-catch
or try-finally statements. When an exception is thrown, the program looks for the catch
statement that handles this exception.
The C# language includes syntax for Structured Exception Handling (SEH). Keywords exist to
mark code out as being able to handle exceptions, along with instructions as to what to do if an
exception occurs. The three keywords you use for this are try, catch, and finally. Each of these
has an associated code block and must be used in consecutive lines of code. The basic structure
is as follows:
try
{
...
}
catch (<exceptionType> e)
{
...
}
finally
{
...
}
It is also possible, however, to have a try block and a finally block with no catch block, or a try
block with multiple catch blocks. If one or more catch blocks exist, then the finally block is
optional, else it is mandatory.
• try: Contains code that might throw exceptions (throw is the C# way of saying generate
or cause when talking about exceptions).
• catch: Contains code to execute when exceptions are thrown. catch blocks may be set to
respond only to specific exception types (such as System.IndexOutOfRangeException)
using <exceptionType>, hence the ability to provide multiple catch blocks. It is also
possible to omit this parameter entirely, to get a general catch block that will respond to
all exceptions.
• finally: Contains code that is always executed, either after the try block if no exception
occurs, after a catch block if an exception is handled, or just before an unhandled
exception terminates the application (the fact that this block is processed at this time is
the reason for its existence; otherwise, you might just as well place code after the block).
The sequence of events that occurs after an exception occurs in code in a try block is:
• The try block terminates at the point where the exception occurred.
• If a catch block exists, then a check is made to see if the block matches the type of
exception that has been thrown. If no catch block exists, then the finally block (which
must be present if there are no catch blocks) executes.
• If a catch block exists, but there is no match, then a check is made for other catch blocks.
• If a catch block matches the exception type, the code it contains executes, and then the
finally block executes if it is present.
• If no catch blocks match the exception type, then the finally block of code executes if it is
present.
MessageBox