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

This is part 4 of the series. Before reading this article, I highly recommend reading the previous parts:

Day 4 Agenda

  1. Delegates
  2. Enums
  3. Attributes
  4. Generics

Delegates

In a single term we can define a Delegate as type safe pointer to a function. Delegates doesn’t work alone it delegates the associated method to work for it.

Syntax:

publicdelegatevoidCall(); //Simple syntax Non Parametrized Delegate


When you want to use the Class in C# you do in the following ways, you first define the class (properties, methods) and then you instantiate the class using object. With delegate it’s 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. Let’s 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.

  1. using System;  
  2.   
  3. namespace Delegates  
  4.   
  5. {  
  6.     public delegate void Dcaller(int Rno, string Ename); //declaring Delegate of type(int,string) same as PrintInformation function  
  7.     class Employee  
  8.     {  
  9.   
  10.         public void PrintInformation(int Rollno, string EmployeeName)   
  11.         {  
  12.             Console.WriteLine("The Roll no of {0} is {1}", EmployeeName, Rollno);  
  13.             Console.ReadLine();  
  14.         }  
  15.     }  
  16.   
  17.   
  18.     class Program {  
  19.         static void Main(string[] args)   
  20.         {  
  21.             Employee obj = new Employee();  
  22.             Dcaller delegateObj = new Dcaller(obj.PrintInformation); //creating object of Delegate and pointing method to it.  
  23.             delegateObj.Invoke(1, "Saillesh"); //Invoking of Delegate  
  24.         }  
  25.     }  
  26. }  
Output:

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.
  1. using System;

  2. namespace Delegates   
  3. {  
  4.     public delegate double Dcalculate(int FirstNum, int SecondNum, int ThirdNum);  
  5.   
  6.     classCalculation  
  7.     {  
  8.         public double Sum(int Num1, int Num2, int Num3)  
  9.         {  
  10.             return Num1 + Num2 + Num3;  
  11.         }  
  12.   
  13.   
  14.         public double Multiplication(int Num1, int Num2, int Num3)  
  15.         {  
  16.             return Num1 * Num2 * Num3;  
  17.         }  
  18.   
  19.     }  
  20.   
  21.   
  22.     classProgram  
  23.     {  
  24.         staticvoid Main(string[] args)  
  25.         {  
  26.             double Result;  
  27.             Calculation obj = newCalculation();  
  28.   
  29.             Dcalculate objDelegate = new Dcalculate(obj.Sum);  
  30.             Result = objDelegate.Invoke(10, 20, 30); //Delegate method is invoked one at a time  
  31.             Console.WriteLine("The sum is={0}", Result);  
  32.             objDelegate = new Dcalculate(obj.Multiplication);  
  33.             Result = objDelegate.Invoke(2, 3, 4);  
  34.             Console.WriteLine("The multiplication result is={0}", Result);  
  35.             sConsole.ReadLine();  
  36.   
  37.   
  38.         }  
  39.     }  
  40. }  
Output:

output
                                      Fig 2.0 Demonstrating Multicast delegate

But if focus on the above program I can achieve the same without using the Delegate

Eg1:
  1. using System;  
  2.   
  3. namespace Delegates  
  4. {  
  5.   
  6.     class Employee   
  7.     {  
  8.   
  9.         public void PrintInformation(int Rollno, string EmployeeName)   
  10.         {  
  11.             Console.WriteLine("The Roll no of {0} is {1}", EmployeeName, Rollno);  
  12.             Console.ReadLine();  
  13.         }  
  14.     }  
  15.   
  16.   
  17.     class Program  
  18.     {  
  19.         static void Main(string[] args)   
  20.         {  
  21.             Employee obj = new Employee();  
  22.             obj.PrintInformation(1, "Saillesh");  
  23.   
  24.         }  
  25.     }  
  26. }  
Output:

output
                                    Fig 3.0 Simple calling of a method

Eg 2:
  1. using System;  
  2.   
  3. namespace Delegates  
  4. {  
  5.     class Calculation  
  6.     {  
  7.         public double Sum(int Num1, int Num2, int Num3)  
  8.         {  
  9.             return Num1 + Num2 + Num3;  
  10.         }  
  11.   
  12.   
  13.         public double Multiplication(int Num1, int Num2, int Num3)  
  14.         {  
  15.             return Num1 * Num2 * Num3;  
  16.         }  
  17.   
  18.     }  
  19.   
  20.   
  21.     class Program  
  22.     {  
  23.         static void Main(string[] args)  
  24.         {  
  25.             double Result;  
  26.             Calculation obj = new Calculation();  
  27.   
  28.             Result = obj.Sum(10, 20, 30);  
  29.             Console.WriteLine("The sum is={0}", Result);  
  30.             Result = obj.Multiplication(2, 3, 4);  
  31.             Console.WriteLine("The multiplication result is={0}", Result);  
  32.             Console.ReadLine();  
  33.   
  34.   
  35.         }  
  36.     }  
  37. }  
Output:

output
                           Fig 4.0 Simple calling of a method

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

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

delegates
            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 Arithmetic 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.
  1. using System.Threading;  
  2.   
  3. namespace Shared.cs   
  4. {  
  5.     public class del  
  6.     {  
  7.         public delegate void WhereTocall(int status);  
  8.         public WhereTocall wheretocall = null;  
  9.         public void Multiplication()  
  10.         {  
  11.             for (int i = 1; i <= 5; i++)  
  12.             {  
  13.                 for (int j = 1; j <= 10; j++)   
  14.                 {  
  15.   
  16.                     int multiply = i * j;  
  17.                     wheretocall(multiply);  
  18.                 }  
  19.   
  20.             }  
  21.   
  22.         }  
  23.   
  24.     }  
  25.   
  26.     public class Arithmetic   
  27.     {  
  28.   
  29.         public delegate void DelPointer(string Multiplication);  
  30.         public DelPointer delpointer = null;  
  31.         public int range  
  32.         {  
  33.             get;  
  34.             set;  
  35.         }  
  36.         public int result   
  37.         {  
  38.             get;  
  39.             set;  
  40.         }  
  41.         public string output  
  42.         {  
  43.             get;  
  44.             set;  
  45.         }  
  46.         public Arithmetic(int upto)  
  47.         {  
  48.             range = upto;  
  49.   
  50.         }  
  51.   
  52.         public void Multiplication()  
  53.         {  
  54.             for (int i = 1; i <= range; i++)  
  55.             {  
  56.   
  57.                 for (int j = 1; j <= 10; j++)   
  58.                 {  
  59.                     result = i * j;  
  60.                     output = i.ToString() + "*" + j.ToString() + "=" + result.ToString();  
  61.                     delpointer.Invoke(output); //delegate invoking  
  62.                     Thread.Sleep(1000);  
  63.                 }  
  64.   
  65.             }  
  66.   
  67.         }  
  68.   
  69.   
  70.     }  
  71. }  
  72.   
  73.   
  74. using static System.Console;  
  75. using Shared.cs;  
  76. namespace DELEGATE  
  77. {  
  78.   
  79.     delegate void somePointer(); //1 declare delegate  
  80.     class Program   
  81.     {  
  82.         static void Main(string[] args)  
  83.         {  
  84.             Arithmetic obj = newArithmetic(5);  
  85.             obj.delpointer = Print;  
  86.             obj.Multiplication();  
  87.             ReadLine();  
  88.         }  
  89.   
  90.         static void Print(string Output)  
  91.         {  
  92.             WriteLine(Output);  
  93.         }  
  94.   
  95.   
  96.     }  
  97. }  

Delegate
               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 it’s better to replace them with Enum, to make the program more readable and maintainable.

Let consider the following example, we have a class called Order Master which has the following properties.
  1. public class OrderMaster  
  2. {  
  3.     public int OrderId   
  4.     {  
  5.         get;  
  6.         set;  
  7.     }  
  8.     public string OrderCreatedby  
  9.     {  
  10.         get;  
  11.         set;  
  12.     }  
  13.     public long MobileNo  
  14.     {  
  15.         get;  
  16.         set;  
  17.     }  
  18.   
  19.     //Status 1:OrderedPlaced  
  20.     //Status 2:OrderAccepted  
  21.     //Status 3:Billed  
  22.     //Status 4:TripCreated  
  23.     //Status 5:Delivered  
  24.     //Status 6:Cancelled  
  25.     public int Status  
  26.     {  
  27.         get;  
  28.         set;  
  29.     }  
  30. }  
Let us take an example when we Order Details to be shared to the User let us try the same:
  1. class Program   
  2. {  
  3.     static void Main(string[] args)   
  4.     {  
  5.   
  6.         //These will retrieved from database and we will print the details to the User that is present in this array  
  7.         //Status field is needed to be shown in String  
  8.   
  9.         OrderMaster[] order = newOrderMaster[3];  
  10.         order[0] = newOrderMaster  
  11.         {  
  12.             OrderCreatedby = "Saillesh Pawar",  
  13.                 MobileNo = 999999999,  
  14.                 OrderId = 001,  
  15.                 Status = 1  
  16.         };  
  17.   
  18.         order[1] = newOrderMaster  
  19.         {  
  20.             OrderCreatedby = "Virender Pawar",  
  21.                 MobileNo = 999999992,  
  22.                 OrderId = 003,  
  23.                 Status = 2  
  24.         };  
  25.   
  26.   
  27.         order[2] = newOrderMaster   
  28.         {  
  29.             OrderCreatedby = "Rakesh Pawar",  
  30.                 MobileNo = 99999993,  
  31.                 OrderId = 004,  
  32.                 Status = 5  
  33.         };  
  34.   
  35.   
  36.   
  37.         //here we are printing the Orders to the User  
  38.         foreach(OrderMaster orderMaster in order)  
  39.         {  
  40.             Console.WriteLine($ "Customer Name {orderMaster.OrderCreatedby} OrderId {orderMaster.OrderId}&& MobileNo {orderMaster.MobileNo}&& Status {orderMaster.Status}");  
  41.   
  42.         }  
  43.     }  
  44. }  

output
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 doesn’t 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.
  1. //inside Void main  
  2. //here we are printing the Orders to the User  
  3. foreach(OrderMaster orderMaster in order)  
  4. {  
  5.     Console.WriteLine($ "Customer Name {orderMaster.OrderCreatedby} OrderId {orderMaster.OrderId}&& MobileNo {orderMaster.MobileNo}&& Status {getStatus(orderMaster.Status)}");  
  6.     //calling getStatus function and passing the value to the method  
  7.   
  8. }  
  9.   
  10. //accepts a int id and returns the corresponding Status   
  11. public static string getStatus(int id)  
  12. {  
  13.   
  14.     switch (id)   
  15.     {  
  16.   
  17.         case 1:  
  18.             return "Ordered Placed";  
  19.         case 2:  
  20.             return "Order Accepted";  
  21.         case 3:  
  22.             return "Billed";  
  23.         case 4:  
  24.             return "Trip Created";  
  25.         case 5:  
  26.             return "Delivered";  
  27.         case 6:  
  28.             return "Cancelled";  
  29.         default:  
  30.             return "Wrong Status";  
  31.     }   
  32.   
  33. }  
output
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 it is showing the status in proper formats. But there are some major concern which make this program 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:
  1. //enum declartion   
  2. public enumStatus   
  3. {  
  4.     //integrals values   
  5. }  
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:
  1. //enum declartion   
  2. public enum Status   
  3. {  
  4.     //numbers denote what status in database mean  
  5.   
  6.     OrderedPlaced = 1,  
  7.         OrderAccepted = 2,  
  8.         Billed = 3,  
  9.         TripCreated = 4,  
  10.         Delivered = 5,  
  11.         Cancelled = 6  
  12.   
  13. };  
  14. public class OrderMaster   
  15. {  
  16.     public int OrderId   
  17.     {  
  18.         get;  
  19.         set;  
  20.     }  
  21.     public string OrderCreatedby  
  22.     {  
  23.         get;  
  24.         set;  
  25.     }  
  26.     public long MobileNo   
  27.     {  
  28.         get;  
  29.         set;  
  30.     }  
  31.     //declaring status of type enum Status  
  32.     public Status status   
  33.     {  
  34.         get;  
  35.         set;  
  36.     }  
  37. }  
  38.   
  39. class Program   
  40. {  
  41.   
  42.     static void Main(string[] args)   
  43.     {  
  44.   
  45.         //These will retrieved from database and we will print the details to the User that is present in this array  
  46.         //Status field is needed to be shown in String  
  47.         //as discussed enum is strongly typed constant so cast is required  
  48.   
  49.         OrderMaster[] order = newOrderMaster[3];  
  50.         order[0] = newOrderMaster   
  51.         {  
  52.             OrderCreatedby = "Saillesh Pawar",  
  53.                 MobileNo = 999999999,  
  54.                 OrderId = 001,  
  55.                 //type casting to enum   
  56.                 status = (Status) 1  
  57.         };  
  58.   
  59.         order[1] = newOrderMaster  
  60.         {  
  61.             OrderCreatedby = "Virender Pawar",  
  62.                 MobileNo = 999999992,  
  63.                 OrderId = 003,  
  64.                 //type casting to enum   
  65.                 status = (Status) 2  
  66.         };  
  67.   
  68.   
  69.         order[2] = newOrderMaster  
  70.         {  
  71.             OrderCreatedby = "Rakesh Pawar",  
  72.                 MobileNo = 99999993,  
  73.                 OrderId = 004,  
  74.                 //type casting to enum   
  75.                 status = (Status) 5  
  76.         };  
  77.   
  78.   
  79.   
  80.         //here we are printing the Orders to the User  
  81.         foreach(OrderMaster orderMaster in order)  
  82.         {  
  83.             Console.WriteLine($ "Customer Name {orderMaster.OrderCreatedby} OrderId {orderMaster.OrderId}&& MobileNo {orderMaster.MobileNo}&& Status {getStatus(orderMaster.status)}");  
  84.   
  85.         }  
  86.   
  87.     }  
  88.   
  89.   
  90.     //accepts enum and returns the corresponding Status   
  91.   
  92.     //now the getStatus method takes enum of type Status  
  93.     public static string getStatus(Status status)   
  94.     {  
  95.   
  96.         switch (status)  
  97.         {  
  98.   
  99.             //Here we can inplace of using 1,2, etc we are using enum   
  100.             //with the help of this code is readable as we are denoting the status easily rather than denoting them with numbers  
  101.   
  102.             case Status.OrderedPlaced:  
  103.                 return "Ordered Placed";  
  104.             case Status.OrderAccepted:  
  105.                 return "Order Accepted";  
  106.             case Status.Billed:  
  107.                 return "Billed";  
  108.             case Status.TripCreated:  
  109.                 return "Trip Created";  
  110.             case Status.Delivered:  
  111.                 return "Delivered";  
  112.             case Status.Cancelled:  
  113.                 return "Cancelled";  
  114.             default:  
  115.             return "Wrong Status";  
  116.         }  
  117.   
  118.     }  
  119.   
  120. }  
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.

output
     Fig 10.0 Understandable demonstration of User Orders with status using enum.

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

Attributes

Attributes are nothing just declarative information which you can attach 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.

Let’s take an example of a Customer class as shown below:
  1. namespace Attributes  
  2. {  
  3.     public class Customer  
  4.     {  
  5.   
  6.         [Key]  
  7.   
  8.         public int CustomerID  
  9.         {  
  10.             get;  
  11.             set;  
  12.         }  
  13.         public string CustomerName  
  14.         {  
  15.             get;  
  16.             set;  
  17.         }  
  18.         public string CustomerAddress  
  19.         {  
  20.             get;  
  21.             set;  
  22.         }  
  23.   
  24.   
  25.         //adding single Customer to Database  
  26.         public void addEmp(Customer cust)  
  27.         {  
  28.   
  29.             //data access layer object  
  30.             DAL dal = newDAL();  
  31.   
  32.             //adding a customer to   
  33.             dal.customer.Add(cust);  
  34.   
  35.             //commiting changes into db  
  36.             dal.SaveChanges();  
  37.   
  38.             //printing the value of the Id generated  
  39.             Console.WriteLine("The Customer has been successfully stored in Db with id " + cust.CustomerID);  
  40.   
  41.         }  
  42.     }  
  43. }  
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
  1. namespace Attributes   
  2. {  
  3.     public classDAL: DbContext   
  4.     {  
  5.         //collection of entitites that can be queried from the db  
  6.         public DbSet < Customer > customer   
  7.         {  
  8.             get;  
  9.             set;  
  10.         }  
  11.   
  12.   
  13.         protected override void OnModelCreating(DbModelBuilder modelBuilder)  
  14.         {  
  15.             //mapping code to tblCustomerMaster table  
  16.             modelBuilder.Entity < Customer > ().ToTable("tblCustomerMaster");  
  17.         }  
  18.     }  
  19. }  
So now when user inserts his details the Customer details is saved into DB.

Here,
  1. class Program   
  2. {  
  3.     static void Main(string[] args)   
  4.     {  
  5.         //create a Customer object  
  6.         Customer obj = newCustomer();  
  7.         Console.WriteLine("Enter the UserName");  
  8.         //set the properties  
  9.         obj.CustomerName = Console.ReadLine();  
  10.         Console.WriteLine("Enter the Address");  
  11.         obj.CustomerAddress = Console.ReadLine();  
  12.         obj.addEmp(obj);  
  13.         Console.ReadLine();  
  14.   
  15.     }  
  16. }  
Now as the user inserts his details the record is saved into the db as shown below:

output
            Fig 12.0 Demonstrating insertion of Customer Details.

Let’s 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:
  1. public class Customer  
  2. {  
  3.   
  4.     [Key]  
  5.   
  6.     public int CustomerID   
  7.     {  
  8.         get;  
  9.         set;  
  10.     }  
  11.     public string CustomerName   
  12.     {  
  13.         get;  
  14.         set;  
  15.     }  
  16.     public string CustomerAddress  
  17.     {  
  18.         get;  
  19.         set;  
  20.     }  
  21.   
  22.   
  23.     //adding single Customer to Database  
  24.     public void addEmp(Customer cust)  
  25.     {  
  26.   
  27.         //data access layer object  
  28.         DAL dal = newDAL();  
  29.   
  30.         //adding a customer to   
  31.         dal.customer.Add(cust);  
  32.   
  33.         //commiting changes into db  
  34.         dal.SaveChanges();  
  35.   
  36.         //printing the value of the Id generated  
  37.         Console.WriteLine("The Customer has been successfully stored in Db with id " + cust.CustomerID);  
  38.   
  39.     }  
  40.   
  41.     public static void addEmpList(List < Customer > custList)  
  42.     {  
  43.   
  44.         DAL dal = newDAL();  
  45.         foreach(Customer cust in custList)  
  46.         {  
  47.             //adding records into entities  
  48.             dal.customer.Add(cust);  
  49.         }  
  50.         dal.SaveChanges();  
  51.   
  52.         //if dal.savechanges returns 0  
  53.         if (dal.SaveChanges() == 0)  
  54.         {  
  55.             //fetch all the records from the database and display to the User  
  56.             List < Customer > lstCus = dal.customer.ToList < Customer > ();  
  57.             foreach(Customer customer in lstCus)  
  58.             {  
  59.                 //printing the Customer records to the User  
  60.                 Console.WriteLine($ "Customer name:{customer.CustomerName} with Id:{customer.CustomerID} lives in {customer.CustomerAddress}");  
  61.   
  62.             }  
  63.   
  64.         }  
  65.   
  66.     }  
  67.   
  68. }  
  69.   
  70.   
  71. class Program  
  72. {  
  73.     static void Main(string[] args)   
  74.     {  
  75.         //create a list Customer object  
  76.         List < Customer > objCustList = newList < Customer > ();  
  77.   
  78.         Console.WriteLine("Enter the list of customers to be added");  
  79.         //will contain number of customer to be added  
  80.         int range = Convert.ToInt32(Console.ReadLine());  
  81.         //for loop till the range is exceeded  
  82.         for (int i = 0; i < range; i++)   
  83.         {  
  84.             //create a customer object  
  85.             Customer customer = newCustomer();  
  86.             Console.WriteLine("Enter the UserName");  
  87.             //set the properties  
  88.             customer.CustomerName = Console.ReadLine();  
  89.             Console.WriteLine("Enter the Address");  
  90.             customer.CustomerAddress = Console.ReadLine();  
  91.             //add customer object to the list of Customer  
  92.             objCustList.Add(customer);  
  93.         }  
  94.         Customer.addEmpList(objCustList);  
  95.         Console.ReadLine();  
  96.   
  97.     }  
  98. }  
Now run the program and we will see the following output, as shown below:

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

Now we can see we have two 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:

  1. [Obsolete]  
  2. //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   
  3.   
  4. [Obsolete]  
  5. public static void addEmp(Customer cust)  
  6. {  
  7.   
  8.     //data access layer object  
  9.     DAL dal = newDAL();  
  10.   
  11.     //adding a customer to   
  12.     dal.customer.Add(cust);  
  13.   
  14.     //commiting changes into db  
  15.     dal.SaveChanges();  
  16.   
  17.     //printing the value of the Id generated  
  18.     Console.WriteLine("The Customer has been successfully stored in Db with id " + cust.CustomerID);  
  19.   
  20. }  
Now if I try to call this method we can see the message is deprecated.


output
Fig 14.0. Demonstrating the deprecated message to the user so that he can understand this method has been removed or old.

output
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?

output
Fig 16.0 Demonstration of Constructor in Obsolete attribute.

There are three overloaded attribute of Obsolete as shown above. Let us see the same:
  1. public ObsoleteAttribute() //default obsolete  
  2. public ObsoleteAttribute(string message); //displaying user defined message alternative workarounds.  
  3. public ObsoleteAttribute(string message, bool error);  
  4. error:  
  5.     // The Boolean value that indicates whether the obsolete element usage is considered  
  6.     // an error.  
  7.   
  8. [Obsolete("Use only addEmpList method ")]  
  9. public static void addEmp(Customer cust)   
  10. {  
  11.   
  12.     //data access layer object  
  13.     DAL dal = newDAL();  
  14.   
  15.     //adding a customer to   
  16.     dal.customer.Add(cust);  
  17.   
  18.     //commiting changes into db  
  19.     dal.SaveChanges();  
  20.   
  21.     //printing the value of the Id generated  
  22.     Console.WriteLine("The Customer has been successfully stored in Db with id " + cust.CustomerID);  
  23.   
  24. }  
Now if the user tries to call the addEmp method he will see a message denoting "Use only addEmpList method” as shown below:


code
                               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:
  1. [Obsolete("Use only addEmpList method "true)]  
  2. public static void addEmp(Customer cust)   
  3. {  
  4.   
  5.     //data access layer object  
  6.     DAL dal = newDAL();  
  7.   
  8.     //adding a customer to   
  9.     dal.customer.Add(cust);  
  10.   
  11.     //commiting changes into db  
  12.     dal.SaveChanges();  
  13.   
  14.     //printing the value of the Id generated  
  15.     Console.WriteLine("The Customer has been successfully stored in Db with id " + cust.CustomerID);  
  16.   
  17. }  
function
        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 us take a scenario what we generally mean 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.

  1. using System;  
  2. using static System.Console;  
  3. namespace sIMPLE  
  4. {  
  5.     class Program  
  6.     {  
  7.         static void Main(string[] args)  
  8.         {  
  9.             //calling static method of CompareClass and passing two integer parameters  
  10.             bool result = CompareClass.Compare(10, 20);  
  11.             Console.WriteLine(result);  
  12.             ReadLine();  
  13.         }  
  14.     }  
  15.   
  16.   
  17.     public class CompareClass  
  18.     {  
  19.   
  20.         //compare method will take two int as a parameter and will return bool value true or false  
  21.         public static bool Compare(int num1, int num2)  
  22.         {  
  23.             return num1 == num2;  
  24.         }  
  25.   
  26.     }  
  27. }  
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:
  1. class Program  
  2. {  
  3.     static void Main(string[] args)   
  4.     {  
  5.         //calling static method of CompareClass and passing two string parameters  
  6.         bool result = CompareClass.Compare("saillesh""saillesh");  
  7.         Console.WriteLine($ "The result of the compare method is {result}");  
  8.         ReadLine();  
  9.     }  
  10. }  
  11.   
  12.   
  13. public class CompareClass   
  14. {  
  15.   
  16.     //compare method will take two string as a parameter and will return bool value true or false  
  17.     public static bool Compare(string str1, string str2)  
  18.     {  
  19.         return str1 == str2;  
  20.     }  
  21. }  

function
         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).
  1. class Program  
  2. {  
  3.     static void Main(string[] args)  
  4.     {  
  5.         //calling static method of CompareClass and passing two object type parameters  
  6.         bool result = CompareClass.Compare("saillesh", 1);  
  7.         Console.WriteLine($ "The result of the compare method is {result}");  
  8.         ReadLine();  
  9.     }  
  10. }  
  11.   
  12.   
  13. public class CompareClass   
  14. {  
  15.   
  16.     //compare method will take two int as a parameter and will return bool value true or false  
  17.     public static bool Compare(object str1, object str2)  
  18.     {  
  19.         return str1 == str2;  
  20.     }  
  21.   
  22. }  

function
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 it’s 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 result in poor performance because when a value type is boxed it is creating 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 it’s 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.

function
Fig 21.0: Demonstrating strongly typed data types are accepted when we use generic of type int.

We can specify the type on the class level also as shown below:
  1. class Program  
  2. {  
  3.     static void Main(string[] args)   
  4.     {  
  5.         //calling static method of CompareClass and passing two object type parameters  
  6.         bool result = CompareClass < int > .Compare(1, 2);  
  7.         Console.WriteLine($ "The result of the int compare method is {result}");  
  8.   
  9.         result = CompareClass < string > .Compare("Saillesh""Pawar");  
  10.         Console.WriteLine($ "The result of the string compare method is {result}");  
  11.         ReadLine();  
  12.     }  
  13. }  
  14.   
  15.   
  16. public class CompareClass < T >  
  17.   {  
  18.   
  19.     //compare method will take two int as a parameter and will return bool value true or false  
  20.     public static bool Compare(T str1, T str2)   
  21.   {  
  22.         return str1.Equals(str2);  
  23.     }  
  24. }  
So, here we learned how we can decouple our logic from the data type with the help of Generic.