Learn Tiny Bit of C# in 7 days - Day2

33
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

Transcript of Learn Tiny Bit of C# in 7 days - Day2

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. Delegates2. Enums3. Attributes4. 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 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 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.

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 let’s 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.

EnumsEnums 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 a below examplewe 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 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.

//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 "Ordered Placed"; case 2: return "Order Accepted"; case 3: return "Billed"; case 4: return "Trip Created"; case 5: return "Delivered"; case 6: return "Cancelled"; default: return "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 it’s 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 User 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)}");

}

}

//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.

AttributesAttributes 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.

Let’s 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.

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:

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.

GenericsGeneric 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 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 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 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.

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.