You are on page 1of 29

Before reading this article, I highly recommend reading my previous parts:

Learn Tiny Bit Of C# In 7 Days - Day 1

Learn Tiny Bit Of C# In 7 Days - Day 2

Learn Tiny Bit Of C# In 7 Days - Day 3

Before moving ahead I would recommend watching videos from below image
for full in depth topics. Just click on the below image you would be navigated
to the Videos.
https://www.youtube.com/playlist?
list=PLqGM4JWKUx3cZKGoy4J9vX4DCBOOjRhJe

Day 4 Agenda
1.
2.
3.
4.

Delegates
Enums
Attributes
Generics

Delegates

In a single term we can define a Delegate as type safe pointer to a


function.

Delegates doesnt work alone it delegates the associated to method to work


for it.

Syntax:

public delegate void Call(); //Simple syntax Non Parametrized Delegate

When you want to use the Class in C# you do in following ways, you first
define the class (properties, methods) and then you instantiate the class
using object. With delegate its the same process. You first declare the
Delegate as shown above i.e. what kind of type will delegate represent.
Then, we have to create one or more instances of that delegate. Lets make
a small program defining the definition that Delegate as type safe pointer to
a function. We will learn how to declare a Delegate, creating object of
Delegate and how to invoke the Delegate.
using System;
namespace Delegates

public delegate void Dcaller(int Rno, string Ename); //declaring Delegate of


type(int,string) same as PrintInformation function
class Employee
{
public void PrintInformation(int Rollno, string EmployeeName)
{
Console.WriteLine("The Roll no of {0} is {1}", EmployeeName, Rollno);
Console.ReadLine();
}
}
class Program
{
static void Main(string[] args)
{
Employee obj = new Employee();
Dcaller delegateObj = new Dcaller(obj.PrintInformation);//creating object of Delegate and
pointing method to it.
delegateObj.Invoke(1, "Saillesh");//Invoking of Delegate
}
}
}

Output:

Fig 1.0: Demonstrating Simple delegate


Associating a Delegate with more than One Method (Multicast
Delegate)
We can associate our Delegate to more than one method. The association
between the delegate and method is created during runtime based on the
return type and its signature.
using System;
namespace Delegates
{
public delegate double Dcalculate(int FirstNum, int SecondNum,int ThirdNum);
class Calculation
{
public double Sum(int Num1, int Num2, int Num3)
{
return Num1+ Num2+ Num3;
}

public double Multiplication(int Num1, int Num2, int Num3)


{
return Num1 * Num2 * Num3;
}
}
class Program
{
static void Main(string[] args)
{
double Result;
Calculation obj = new Calculation();
Dcalculate objDelegate = new Dcalculate(obj.Sum);
Result= objDelegate.Invoke(10,20,30); //Delegate method is invoked one at a time
Console.WriteLine("The sum is={0}",Result);
objDelegate = new Dcalculate(obj.Multiplication);
Result = objDelegate.Invoke(2,3,4);
Console.WriteLine("The multiplication result is={0}",Result);
sConsole.ReadLine();

Output:

Fig 2.0 Demonstrating Multicast delegate


But if focus on the above program I can achieve the same without using the
Delegate
Eg1:
using System;
namespace Delegates
{
class Employee
{
public void PrintInformation(int Rollno, string EmployeeName)
{

Console.WriteLine("The Roll no of {0} is {1}", EmployeeName, Rollno);


Console.ReadLine();
}

class Program
{
static void Main(string[] args)
{
Employee obj = new Employee();
obj.PrintInformation(1, "Saillesh");
}
}

Output:

Fig 3.0 Simple calling of a method

Eg 2:
using System;
namespace Delegates
{

class Calculation
{
public double Sum(int Num1, int Num2, int Num3)
{
return Num1 + Num2 + Num3;
}
public double Multiplication(int Num1, int Num2, int Num3)
{
return Num1 * Num2 * Num3;
}
}
class Program
{
static void Main(string[] args)

double Result;
Calculation obj = new Calculation();
Result = obj.Sum(10, 20, 30);
Console.WriteLine("The sum is={0}", Result);
Result = obj.Multiplication(2,3,4);
Console.WriteLine("The multiplication result is={0}", Result);
Console.ReadLine();

}
}

Output:

Fig 4.0 Simple calling of a method


So we figured it out we can achieve the same without using delegate, so lets
focus what actually does delegate means in common language. Delegates
mean communication between two parties.

Fig 5.0 we can see two countries delegate communicating with each
other.

Fig 6.0 Demonstration of official Delegate meetings being held in


Uttrakhand.
In Windows we have seen Callbacks. Callbacks are method calls that are
executed when some event happens during execution.
In computer programming, a callback is executable code that is passed as an
argument to other code.- Wikipedia
Eg: you want to delegate the long running operation to a background thread
while allowing user interface responsive, However when the execution is
running we want to check the status of execution time by time.
Here I am demonstrating small example where I have created a class Called
Arithmatic with function named Multiplication method which will perform
multiplication Table of the range send by user.
Here this function is called via thread which will run at background, while the
process is being running with the help of delegate we will be able to check
the status and execution steps with the help of callback as shown below.
using System.Threading;
namespace Shared.cs

public class del


{
public delegate void WhereTocall(int status);
public WhereTocall wheretocall = null;
public void Multiplication()
{
for (int i = 1; i <= 5; i++)
{
for (int j = 1; j <= 10; j++)
{
int multiply = i * j;
wheretocall(multiply);
}
}
}
}
public class Arithmetic
{
public delegate void DelPointer(string Multiplication);
public DelPointer delpointer = null;
public int range { get; set; }
public int result { get; set; }
public string output { get; set; }
public Arithmetic(int upto)
{
range = upto;
}
public void Multiplication()
{
for (int i = 1; i <= range; i++)
{
for (int j = 1; j <= 10; j++)
{
result = i * j;
output = i.ToString() + "*" + j.ToString() + "=" + result.ToString();
delpointer.Invoke(output); //delegate invoking
Thread.Sleep(1000);
}
}
}

using static System.Console;


using Shared.cs;
namespace DELEGATE
{
delegate void somePointer();//1 declare delegate
class Program
{
static void Main(string[] args)
{
Arithmetic obj = new Arithmetic(5);
obj.delpointer = Print;
obj.Multiplication();
ReadLine();
}
static void Print(string Output)
{
WriteLine(Output);
}

}
}

Fig 7.0 Delegate callback method demonstration.

So by this we can conclude that basically delegates are generally used for
communication between two parties i.e. Callbacks and Callbacks.

Enums
Enums are basically strongly typed constants.
If the programs contains set of integral values its better to replace them
with Enum, to make the program more readable and maintainable.

Let consider a below example


we have a class called Order Master which has following properties.

public class OrderMaster


{
public int OrderId { get; set; }
public string OrderCreatedby { get; set; }
public long MobileNo { get; set; }

//Status 1:OrderedPlaced
//Status 2:OrderAccepted
//Status 3:Billed
//Status 4:TripCreated
//Status 5:Delivered
//Status 6:Cancelled
public int Status { get; set; }

Let take an example when we Order Details to be shared to the User let try
the same:
class Program
{
static void Main(string[] args)
{
//These will retrieved from database and we will print the details to the User that is
present in this array
//Status field is needed to be shown in String

OrderMaster[] order = new OrderMaster[3];


order[0] = new OrderMaster
{
OrderCreatedby="Saillesh Pawar",
MobileNo=999999999,
OrderId=001,
Status=1
};
order[1] = new OrderMaster
{
OrderCreatedby = "Virender Pawar",
MobileNo = 999999992,
OrderId = 003,
Status = 2
};
order[2] = new OrderMaster
{
OrderCreatedby = "Rakesh Pawar",
MobileNo = 99999993,
OrderId = 004,
Status = 5
};

//here we are printing the Orders to the User


foreach(OrderMaster orderMaster in order)
{
Console.WriteLine($"Customer Name {orderMaster.OrderCreatedby} OrderId
{orderMaster.OrderId} && MobileNo {orderMaster.MobileNo} && Status {orderMaster.Status}");
}

}
}

Fig 8.0. Demonstration of User Output which seems to be beyond


one to understand the Status field.

As we can see the output screen, it doesnt make sense, as status is 1, 2,


and 5. How could user recognize what does 1, 2 and 5 means? So to make
more User friendly we create a function and return the corresponding status
value and print it to the User screen.

//Inside Void main


//here we are printing the Orders to the User
foreach(OrderMaster orderMaster in order)
{
Console.WriteLine($"Customer Name {orderMaster.OrderCreatedby} OrderId
{orderMaster.OrderId} && MobileNo {orderMaster.MobileNo} && Status
{getStatus(orderMaster.Status)}");
//calling getStatus function and passing the value to the method
}

//accepts a int id and returns the corresponding Status


public static string getStatus(int id)
{
switch(id)
{

}
}

case 1:
return
case 2:
return
case 3:
return
case 4:
return
case 5:
return
case 6:
return
default:
return

"Ordered Placed";
"Order Accepted";
"Billed";
"Trip Created";
"Delivered";
"Cancelled";
"Wrong Status";

Fig 9.0 Understandable demonstration of User Orders with status


but lots of not easily understandable case structure.
Now the output is appropriate for the User as its is showing the status in
proper formats. But there are some major concern which make this program
an unmaintainable. For example in future more status comes in we need to
check into documentation or db to check the values correspond to which
status. In these conditions when we have set of integral values, consider
replacing them with enum as shown below:
Declaration:
//enum declartion
public enum Status
{
//integrals values
}

By default they start with 0 and the value of each successive enum is
increased by 1 however you can specify the same as per your need.

Problem solving:
//enum declartion
public enum Status
{
//numbers denote what status in database mean
OrderedPlaced = 1,
OrderAccepted = 2,
Billed = 3,
TripCreated = 4,
Delivered = 5,
Cancelled = 6
};
public class OrderMaster
{
public int OrderId { get; set; }
public string OrderCreatedby { get; set; }
public long MobileNo { get; set; }
//declaring status of type enum Status
public Status status{ get; set; }

class Program
{
static void Main(string[] args)
{
//These will retrieved from database and we will print the details to the
that is present in this array
//Status field is needed to be shown in String
//as discussed enum is strongly typed constant so cast is required
OrderMaster[] order = new OrderMaster[3];
order[0] = new OrderMaster
{
OrderCreatedby = "Saillesh Pawar",
MobileNo = 999999999,
OrderId = 001,
//type casting to enum
status = (Status)1
};
order[1] = new OrderMaster
{
OrderCreatedby = "Virender Pawar",
MobileNo = 999999992,
OrderId = 003,
//type casting to enum
status = (Status)2
};
order[2] = new OrderMaster
{
OrderCreatedby = "Rakesh Pawar",
MobileNo = 99999993,
OrderId = 004,
//type casting to enum
status = (Status)5
};

//here we are printing the Orders to the User


foreach (OrderMaster orderMaster in order)
{
Console.WriteLine($"Customer Name {orderMaster.OrderCreatedby} OrderId
{orderMaster.OrderId} && MobileNo {orderMaster.MobileNo} && Status
{getStatus(orderMaster.status)}");
}

User

//accepts enum and returns the corresponding Status


//now the getStatus method takes enum of type Status
public static string getStatus(Status status)
{
switch (status)
{
//Here we can inplace of using 1,2, etc we are using enum
//with the help of this code is readable as we are denoting the status easily rather than
denoting them with numbers

case Status.OrderedPlaced:
return "Ordered Placed";
case Status.OrderAccepted:
return "Order Accepted";
case Status.Billed:
return "Billed";
case Status.TripCreated:
return "Trip Created";
case Status.Delivered:
return "Delivered";
case Status.Cancelled:
return "Cancelled";
default:
return "Wrong Status";

}
}

Now once we run our program we will find the same output as before but we
can see our code is better readable, understandable and easy to maintain if
any changes are done.

Fig 10.0 Understandable demonstration of User Orders with status


using enum.

Fig 11.0: Difference between case without enum and with enum,
enum seems to be more readable as compared to without Enum.

Attributes
Attributes are nothing just declarative information which you can attached to
your program (i.e. class, property, method) and we can act on it. Attribute is
a class which inherits from system.Attribute class. It is denoted by [] square
brackets tag.

Lets take an example of a Customer class as shown below:

namespace Attributes
{
public class Customer
{

[Key]
public int CustomerID { get; set; }
public string CustomerName { get; set; }
public string CustomerAddress { get; set; }

//adding single Customer to Database


public void addEmp(Customer cust)
{
//data access layer object
DAL dal = new DAL();
//adding a customer to
dal.customer.Add(cust);
//commiting changes into db
dal.SaveChanges();
//printing the value of the Id generated
Console.WriteLine("The Customer has been successfully stored in Db with id
"+cust.CustomerID);
}

}
}

Here in Customer Class we have a method called addEmp() which inserts an


Employee to the DB. I am using Entity framework to insert values into the db.

DAL Class

namespace Attributes
{
public class DAL:DbContext
{
//collection of entitites that can be queried from the db
public DbSet<Customer> customer { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)

{
}
}

//mapping code to tblCustomerMaster table


modelBuilder.Entity<Customer>().ToTable("tblCustomerMaster");

So now when user inserts his details the Customer details is saved into DB.
Here

class Program
{
static void Main(string[] args)
{
//create a Customer object
Customer obj = new Customer();
Console.WriteLine("Enter the UserName");
//set the properties
obj.CustomerName = Console.ReadLine();
Console.WriteLine("Enter the Address");
obj.CustomerAddress = Console.ReadLine();
obj.addEmp(obj);
Console.ReadLine();
}
}

Now as the User Inserts his details the record is saved into the db. As shown
below:

Fig 12.0 Demonstrating insertion of Customer Details.

Lets assume now we want to insert the list of Customer rather than single
customer so now we create a new method to insert the list of Customers as
shown below:

public class Customer


{
[Key]
public int CustomerID { get; set; }
public string CustomerName { get; set; }
public string CustomerAddress { get; set; }

//adding single Customer to Database


public void addEmp(Customer cust)
{
//data access layer object
DAL dal = new DAL();
//adding a customer to
dal.customer.Add(cust);
//commiting changes into db
dal.SaveChanges();
//printing the value of the Id generated
Console.WriteLine("The Customer has been successfully stored in Db with id
"+cust.CustomerID);
}
public static void addEmpList(List<Customer> custList)
{
DAL dal = new DAL();
foreach(Customer cust in custList)
{
//adding records into entities
dal.customer.Add(cust);
}
dal.SaveChanges();
//if dal.savechanges returns 0
if(dal.SaveChanges()==0)
{
//fetch all the records from the database and display to the User
List<Customer> lstCus = dal.customer.ToList<Customer>();
foreach(Customer customer in lstCus)
{

//printing the Customer records to the User


Console.WriteLine($"Customer name:{customer.CustomerName} with Id:
{customer.CustomerID} lives in {customer.CustomerAddress}");
}
}
}
}

class Program
{
static void Main(string[] args)
{
//create a list Customer object
List<Customer> objCustList = new List<Customer>();
Console.WriteLine("Enter the list of customers to be added");
//will contain number of customer to be added
int range =Convert.ToInt32(Console.ReadLine());
//for loop till the range is exceeded
for(int i=0;i<range;i++)
{
//create a customer object
Customer customer = new Customer();
Console.WriteLine("Enter the UserName");
//set the properties
customer.CustomerName = Console.ReadLine();
Console.WriteLine("Enter the Address");
customer.CustomerAddress = Console.ReadLine();
//add customer object to the list of Customer
objCustList.Add(customer);
}
Customer.addEmpList(objCustList);
Console.ReadLine();
}

Now run the program and we will see the following output, as shown below:

Fig 13.0 Records after trying new method for adding list of
Customers to the db.

Now we can see we have to methods namely:

addEmpList //for adding list of Customer to the database


addEmp //for adding a customer to the database

As we can see in the code that addEmp is an outdated function because it


can handle only one Customer while in addEmpList it can handle up to n
Customer. So we want users to use our addEmpList method rather than
addEmp method. So I want to restrict the user in order not to user addEmp
method, so here where Attribute comes into picture. As definition says
attribute is a declarative information which you can specify to your
programs.
Eg:
[Obsolete]
//Obsolete attribute generates the compile time warning or error based upon
the type of constructor is used of Obsolete.
So now I tag Obsolete on the top of my addEmp method

[Obsolete]
public static void addEmp(Customer cust)

{
//data access layer object
DAL dal = new DAL();
//adding a customer to
dal.customer.Add(cust);
//commiting changes into db
dal.SaveChanges();
//printing the value of the Id generated
Console.WriteLine("The Customer has been successfully stored in Db with id
"+cust.CustomerID);
}

Now if I try to call this method we can see the message is deprecated.

Fig 14.0. Demonstrating the Deprecated message to the User so


that he can understand this method has been removed or old.

Fig 15.0 You need to replace this with new function

If we try to use it still, it will show a warning. What if we want to restrict the
User from using and want to send him alternative workarounds for this
method?

Fig 16.0 Demonstration of Constructor in Obsolete attribute.

There are three overloaded attribute of Obsolete as shown above. Let see
the same:
public ObsoleteAttribute()//default obsolete
public ObsoleteAttribute(string message); //displaying user defined
message alternative workarounds.
public ObsoleteAttribute(string message, bool error);
error:
//
The Boolean value that indicates whether the obsolete element
usage is considered
//
an error.

[Obsolete("Use only addEmpList method ")]


public static void addEmp(Customer cust)
{
//data access layer object
DAL dal = new DAL();
//adding a customer to
dal.customer.Add(cust);
//commiting changes into db
dal.SaveChanges();
//printing the value of the Id generated
Console.WriteLine("The Customer has been successfully stored in Db with id
"+cust.CustomerID);
}

Now if the user tries to call the addEmp method he will see a message
denoting ("Use only addEmpList method as shown below:

Fig 17.0 Showing the Developer which method to use.


Now restricting user to use it by showing error we will use 3 overload of
attribute and use error true:
[Obsolete("Use only addEmpList method ",true)]
public static void addEmp(Customer cust)
{
//data access layer object
DAL dal = new DAL();
//adding a customer to
dal.customer.Add(cust);
//commiting changes into db
dal.SaveChanges();
//printing the value of the Id generated
Console.WriteLine("The Customer has been successfully stored in Db with id
"+cust.CustomerID);
}

Fig 18.0 Not allowing the developer if he/she tries to use the
obsolete function.

There are various attributes that are already defined in .net


Some of them as shown below:

[Web Method]: to expose method over a Web Service.


[Key] in entity Framework: Denotes one or more properties that
uniquely identify an entity.
[Required]: validation for property not to be null
[MaxLength(10)] validation for property whose max length should be
10.

Generics

Generic was added to 2.0 framework, it is the concept of separating


logic from your data type which means we can delay the declaration of
our data type in our class or methods until it is being called by the
client.
Let take a scenario what we generally means by Generics.
We want to have a simple compare function which compares two
integer value as shown below which returns a Boolean value true or
false for the same.
using System;
using static System.Console;
namespace sIMPLE
{
class Program
{
static void Main(string[] args)
{
//calling static method of CompareClass and passing two integer parameters
bool result = CompareClass.Compare(10, 20);
Console.WriteLine(result);
ReadLine();
}
}
public class CompareClass
{
//compare method will take two int as a parameter and will return bool value true or false
public static bool Compare(int num1,int num2)
{
return num1 == num2;

}
}

What if we want to do the same for String values i.e. we need to create
the same method which accepts string as parameter as shown below:
class Program
{
static void Main(string[] args)
{
//calling static method of CompareClass and passing two string parameters
bool result = CompareClass.Compare("saillesh", "saillesh");
Console.WriteLine($"The result of the compare method is {result}");
ReadLine();
}
}
public class CompareClass
{
//compare method will take two string as a parameter and will return bool value true or false
public static bool Compare(string str1,string str2)
{
return str1 == str2;
}
}

Fig 19.0: Demonstration of compare function on string values.


What if we want our method to accept separate our Compare data type the
declaration of our data type to be anything i.e. it can be int, string, double
etc.
How about trying it by using object parameters (as are base class is
object)

class Program
{
static void Main(string[] args)
{
//calling static method of CompareClass and passing two object type parameters
bool result = CompareClass.Compare("saillesh", 1);
Console.WriteLine($"The result of the compare method is {result}");
ReadLine();
}
}
public class CompareClass
{
//compare method will take two int as a parameter and will return bool value true or false
public static bool Compare(object str1,object str2)
{
return str1 == str2;
}
}

Fig 20.0 Demonstration of object type compare which results in poor


performance due to boxing and unboxing.

We may however be able to compare the object types but its seems
foolish to allow numbers and string compared to each other as we did
above, Apart from that we are performing boxing and unboxing which
may results in poor performance because when a value typed is boxed
it is created a new object which takes a long time as compared to
simple reference.
So in order to avoid boxing and unboxing, In order to take the strongly
typed data type Generics comes into picture which can delay the
declaration of data type to be strongly typed in our class or method
until its called by the client(or during the runtime).
Declaration of using a Generic type in C#
public static bool Compare<T>(T str1,T str2)

Here <T> is declaration defining a Generic Type it can be anything as


per your naming conventions.

But when client want to consume this method he needs to declare or


define the type as shown below:
bool result = CompareClass.Compare<int>(1, 1);

This simply implies that we want to compare two integer values.


bool result = CompareClass.Compare<string>("Saillesh", "pawar");

Compare two string values.


But in our compare function we will not be able to perform == so in
place of that we will do
return str1.Equals(str2);
Which will return the true or false. Now with the help of using Generic
we can separate our logic from the data type.

If we try to use define the int type data type and try to pass
string in one parameter we face compile time error.

Fig 21.0: Demonstrating strongly typed data types are accepted


when we us generic of type int.
We can specify the type on the class level also as shown below:
class Program
{
static void Main(string[] args)

//calling static method of CompareClass and passing two object type parameters
bool result = CompareClass<int>.Compare(1, 2);
Console.WriteLine($"The result of the int compare method is {result}");
result = CompareClass<string>.Compare("Saillesh","Pawar");
Console.WriteLine($"The result of the string compare method is {result}");
ReadLine();

public class CompareClass<T>


{
//compare method will take two int as a parameter and will return bool value true or false
public static bool Compare(T str1,T str2)
{
return str1.Equals(str2);
}
}

So here we learn how we can decouple our logic from the data type with the
help of Generic.

You might also like