Cheap Web Hosting Providers
C# Programming‎ > ‎

CSharp Study Notes


Program entry points

using System;
public class HelloWorld
{
        private static void Main(string[] pm)
        {
        Console.WriteLine("Hw");
        }   
}

public class HW2
{
        private static void Main(string[] pm)
    {
        Console.WriteLine("Hw2");
    }
}

Above c# file has two classes in it both having entry points. If you try to compile it you will get error messages. However we can compile it by explicitly stating required entry point as shown below

csc /main:HW2 hw.cs

Nullable Types

Primitive type / value types cannot have null values. Example you cannot assign null value to i in this case int i; To assign null values you have to declare i as nullable type.

Nullable types are objects of System.Nullable<T>, where T must be a value type

A nullable type can be created two different ways. First, you can explicitly declare objects of type Nullable<T>, which is defined in the System namespace. For example, this creates int and bool nullable types:

System.Nullable<int> count;
System.Nullable<bool> done;
Second way is to declare a nullable type, simply follow the type name with a ?.
int? i;

Symbol ? is used to declare nullable types. When a type is declared as nullable type it has a two extra properties, HasValue and Value. HasValue a read only property indicate whether variable has value or its null. Value property gives value of variable and raises exception if accessed when hasvalue is false.



?? is used as  coalescing operator i.e. combining operator

Example
static void Main() {
int? variablea=null;
Console.WriteLine(variablea.HasValue); // false
int variableb=variablea??5;
Console.WriteLine(variableb); // 5
}

Here ?? checks if variablea is null, if its null then it returns default value which is defined after ??.

Example 2
private static void Main(string[] pm)
{
int? a;
a=5;
Console.WriteLine(a??2);
int? b=null;
Console.WriteLine(b??10);

}
Output:
5
10

Important points on Nullable types

  1. Nullable objects does not automatically contain null when its created, hence its common practice to assign null at declaration eg. int? i=null;
  2. When non-nullable and nullable types are mixed in operation, resultant is null value.
  3. Right hand expression of ?? is evaluated only if left expression does not have value.
  4. When two nullable objects are used in relational expression, result is always null when either of the two is null.
  5. Nested nullable types are not allowed. The following line will not compile: Nullable<Nullable<int>> n;


Read-Only Fields of Class

accessibility modifier type fieldname=initialization;

Fields of class can have following modifiers: new, static, read-only, and volatile.

When field is declared as read-only type its value can be only changed in constructor or value can be assigned only while defining. It's value cannot be changed in function members or event handlers.

Difference between constant & read-only members
 Constant    fields Read-only fields
 Value assigned during declaration
 Value can be assigned at declaration or in constructor    
 Value assigned at compile time            
 Value can be assigned at compile as well as runtime
 Constant members are static fields    
 Read-only fields can be static as well as instance members
 Can be initialised only with constant expression    
 can be initialised with non constant expression
   
Code Sample:
using System;


public class HW2
{
    public readonly int ronly=10;
    HW2(int no)
    {
        Console.WriteLine(this.ronly);
        this.ronly=no;
    }
        private static void Main(string[] pm)
    {
        HW2 mHw = new HW2(30);

        Console.WriteLine(mHw.ronly);


    }
}

Output:
10
30

Local Variables

modifier type variablename=initialization;

Note there is no accessibility defination for local variables. all local variables are visible within the scope and has life till the end of scope and are not accessible outside the scope. Method can have same variable as class variable in that case class variable is hidden inside the method and is not accessible.

Sample Code:

using System;

public class HW2
{
    static string a1="Defined in Field";
    public static void scopeTest(int arg)
    {
        //Console.WriteLine(a1);  a1 is treated as local variable since class level a1 automatically gets  hiddden after a1 is declared in method and this line gives error, variable not initialised yet.

        string a1="Inside parent method";
        Console.WriteLine(a1);

    /*    below code will generate compile time error "same variable defined at same scope level"
        {
        int a1=7;
        Console.WriteLine(a1);
        }
        */
       
        childFunc();
    }
   

    public static void Main(string[] args)
    {
        scopeTest(20);
        Console.WriteLine(a1);
    }

    public static void childFunc()
    {
        string a1="Inside child method";
        Console.WriteLine(a1);
        {
         int a2=20;
         Console.WriteLine(a2);
        }
        //Console.WriteLine(a2);  since a2 is not visible outside the scope
    }
}

Output:
Inside parent method
Inside child method
20
Defined in Field

Singletone Pattern

This pattern is used to restrict instantiation of class only once i.e. calling program cannot create two objects of this class. Whenever there is request for second object, this pattern cancels the request and return reference of first object. This is useful when creation of object takes lot of resources or restricted resources e.g. base 3d game class.

Singleton is implemented by creating a class level private instance of the class and converting constructor of class to private. Hence it is not possible to create objects of this class using new keyword. To create object, a static method of class is called which returns reference of above static object.

Singletone class

using System;

public class Starter
{
    public int field1=0;
    private static Starter inst = new Starter();

    public Starter() { }

    public void SetField1(int no)
    {
        this.field1 = no;
    }

    public static Starter GetInstance()
    {
        return inst;
    }

    public static void Main(string[] args)
    {
        Starter s1 = Starter.GetInstance();
        s1.SetField1(15);
        Console.WriteLine(s1.field1);
        Starter s2 = Starter.GetInstance();
        Console.WriteLine(s2.field1);
       
    }
}                                                                                      


Class Function Members

Function Parameters: A function can have zero or more number of parameters. Parameters can be passed either by reference or by value. By default value type parameters are passed by value and reference types by reference (Theoretically reference types are also passed by value i.e copy of reference pointer is passed to function and since this copy also refers to same location, changes any done in function are seen in calling code) .

To explicitly pass parameters by reference, parameter is prefixed with keyword ref. Also keyword out is used. The main difference between out and ref is that parameters need not be initialized before passing to function. But it is important that out parameters be initialized in the function before it is exited.

Sample Code
using System;

public class car
{
    public string carname;
    public string price;

}


public class Test
{
 public static void alterCar(car mcar,int i,ref int k)
    {
      mcar.carname="name changed";
      i=100;
      k=100;
    }

 public static void Main(string[] args)
    {
      int j=10;
      int l=10;
      car mycar=new car();
      mycar.carname="alto";
      mycar.price="2lac";
      alterCar(mycar,j,ref l);
      Console.WriteLine(mycar.carname);  //name changed
      Console.WriteLine(mycar.price);
      Console.WriteLine("Value type passed by value     with initial value=10, now has value=" + j.ToString());   //10
      Console.WriteLine("Value type passed by reference with initial value=10, now has value=" + l.ToString()); //100
     }

}

output:


name changed 
2lac
Value type passed by value     with initial value=10, now has value=10
Value type passed by reference with initial value=10, now has value=100

Properties:

Property syntax:

        accessibility modifier type propertyname

        {

        attributes get {getbody}

        attributes set {setbody}

         }

By default property has public access. A property can have following modifiers
  1. Static : When used, property belongs to class
  2. Virtual : The property's implementation can be changed by an overriding property in a derived class.
  3. Abstract: The property is a member of an abstract class. If the class to which you are adding the property is not abstract, this option is not available.

Properties are set or get methods which can be used to manipulate class fields in a more safer way. Following are the advantages:
  • Properties are safer than public fields. Use the set method to validate the data. If data found incorrect then it can be discarded.

  • Properties can be computed, which adds flexibility. Fields represent a data store and never a calculation. Example get Fullname property can be computed property which splits the name and returns the first part of name though there is just a single variable of name having first and last name details. Public field cannot do this on its own.

  • Lazy initialization can be used with properties. Some data is expensive to obtain. A large dataset is an ideal example. Deferring that cost until necessary is a benefit.

  • Write- and read-only properties are supported. Public fields are fully accessible.

  • Properties are valid members of an interface. As part of the interface contract, a class can be required to publish a property. Interfaces do not include fields.

     ** Lazy initialization is the tactic of delaying the creation of object, the calculation of value, or some other expensive process until the first time it is needed.

Error handling during setting of incorrect value: There are two approaches for it, one by assigning null value, two by raising exception. Both are shown below

Raising error :

private int prop_age;
public int age {
    set {
        if(value<0 || value>120) {
            throw new ApplicationException("Not valid age!");
        }
        prop_age=value;
    }
    get {
        return prop_age;
    }
}

Assigning null value:

public class Person {
    private int? prop_age;
    public int? age {
        set {
           if(value<0 || value>120) {
              prop_age=null;
                             return;
            }
            prop_age=value;
        }
        get {
            return prop_age;
        }
    }
}


Nested Classes / Types
Nested types are classes and structures declared inside class. They have following advantages (INCOMPLETE)
  1. Advantageous when modeling system of interconnected components. 

Example of nested class:
Let us consider the design of a car in which outer class will be Car class which has four wheels. Here wheel is inner or nested class. So car class has four instances of wheel class and wheel instances are connected components of car instance. Since wheel instances have no meaning without car, wheel cars can be best defined using nested classes. Following are note worthy points
1. Wheel instances are alive as long as car instance exists.
2. Car can ask wheel to take certain action such as accelerate, brake, rotate at certain rpm. This are public actions of wheel class
3. Wheel has access to all members of car class.

Sample Code:

using System;

public class Automobile
{
    private bool prop_started=false; 
    private Starter str;  // instance of inner class
    public void Start()
        {
          str=new Starter(this);  //passes refrence of outer instance to inner class
          str.Ignite();
        }
   
     private class Starter  // class can be private, outer class can access,but other class will not be able to access
    {   
        Automobile auto;
        public Starter(Automobile p_auto)
        {
            auto=p_auto;
        }   
       
         internal void Ignite()    //only internal or public accessible members available to outer class
        {
            // code to do starting actions ie. get fuel, ignite spark plugs etc, on success change
            // property of automobile class to stared to true
            auto.prop_started=true;  //can access private members of outer class

        }
   
    }

    public static void Main(String[] args)
    {
        Automobile am=new Automobile();
        am.Start();
        Console.WriteLine("am.started status="+am.prop_started.ToString());

    }
}

Output:
am.started status=True


Visibility Details:
  1. Inner class has access to all members of outer class, even its private members
  2. Outer class cannot access private/protected members of inner class, inner class is just like another class and all other access rules are applicable while accessing members of inner class.
  3. For inner class to access members of outer class, it should get reference of outer class through keyword this.


Partial Classes

Partial class is a normal class with a keyword partial prefixed. When class is converted to partial class its code can be written in more than one file or at more than one place in a single file.

Advantages are :
  1. Many developers can work simulatenously on same class on different functionality in different source files. There is no need to copy this code into single file, compiller does this by merging all the code before compillation and then proceeds with normal compilation procedure.
  2. Helps code generators to split generated code and developer code into different files so that developer does not change the generated code accidentaly.
  3. Helps to split large class file into smaller files.

Points of interest:
  • Member declared in any of the source file can be used in other files. i.e. if int a declared in test1.cs it can be accessed in test2.cs
  • Duplicate fields or functions not allowed
  • Partial methods not supported in C# 2.0, this is a new feature in c# 3.0
  • class access modifiers should be same at every place.

Sample code:

Source file Test.cs

using System;

internal partial class Part1
{    int var1=10;
    public void P1Method()
    {
        Console.WriteLine("P1METHOD EXECUTED");
    }

    public static void Main(string[] args)
    {
      Part1 p=new Part1();
      p.P1Method();
      p.ExtendedMethod();
    }
}

 partial class Part1
{   
    // double var1=20;     Note: cannot redefine member with same name again, will get compile time error
    private void ExtendedMethod()
    {
        Console.WriteLine("Extended Method Executed");
        Console.WriteLine(var1);                             //defined in other part but accessible here
        P3Method();                                              //method defined in other source file
    }
}

Source file test2.cs

using System;

partial class Part1
{
    public void P3Method()
    {
     Console.WriteLine("Method P3 Executed");
    } 

}


Enumerations

An enumeration is a set of named integer constants.

     accessibility enum enumname: basetype {memberlist};


By default enumeration members are of int type. We can change type to any integer type except char. To specify other type suffix enumerator name with colon and type. eg.  enum Apple : byte { Jonathan, GoldenDel, RedDel, Winesap, Cortland, McIntosh };





Comments