Showing posts with label Generics. Show all posts
Showing posts with label Generics. Show all posts

Tuesday, February 28, 2012

Generic Collections

In previous post we talked about Arrays and a special collection object called an ArrayList. We also saw some of the benefits and drawbacks of each approach. Today we will talk about generic collections and how you can use them to create a collection of a specific type and add objects of that particular type to this collection.

We will also talk about how you can pass a collection of any type to a generic method and then inspect the type and do something with it.

Generic Collections
Lets assume you have the following class...

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace GenericsTest
{
    public class Sales
    {
        private string _salesAssociate;
        private double _projected;
        private double _actual;

        public String SalesAssociate
        {
            get { return _salesAssociate; }
            set { _salesAssociate = value; }
        }
        public double Projected
        {
            get { return _projected; }
            set { _projected = value; }
        }
        public double Actual
        {
            get { return _actual; }
            set { _actual = value; }
        }
    }
}

Let's create another class...

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace GenericsTest
{
    public class Salary
    {
        private string _salesAssociate;
        private double _baseSalary;
        private double _commission;

        public String SalesAssociate
        {
            get { return _salesAssociate; }
            set { _salesAssociate = value; }
        }
        public double BaseSalary
        {
            get { return _baseSalary; }
            set { _baseSalary = value; }
        }
        public double Commission
        {
            get { return _commission; }
            set { _commission= value; }
        }
    }
}

Let's build a collection of these objects. We will create two generic collections - each of specific type i.e. Sales and Salary. Notice, that since the collection is of specific type, you cannot mix and match the objects. Although there are ways to do that, but we will cover it in future posts.

using System;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Text;

namespace GenericsTest
{
    class Program
    {
        static void Main(string[] args)
        {
            //declare generic list of type sales
            List<Sales> lstSales = new List<Sales>();
            List<Salary> lstSalary = new List<Salary>();

           //lets add few objects to these collections
            Sales oSales = new Sales();
            oSales.SalesAssociate = "Mike Smith";
            oSales.Projected = 1000;
            oSales.Actual = 1150;
            //Add to collection
           lstSales.Add(oSales);

           //add another object
            Sales oSales1 = new Sales();
            oSales1.SalesAssociate = "Patty Smith";
             oSales1.Projected = 1200;
            oSales1.Actual = 1350;
            //Add to collection
            lstSales.Add(oSales);

           //lets add few objects to another collection
            Salary oSalary = new Salary();
            oSalary.SalesAssociate = "Mike Smith";
            oSalary.BaseSalary= 500;
            oSalary.Commission= 200;
            //Add to collection
           lstSalary.Add(oSalary);

           //add another object
            Salary oSalary1 = new Salary();
            oSalary1.SalesAssociate = "Patty Smith";
            oSalary1.BaseSalary= 500;
            oSalary1.Commission= 275;
            //Add to collection
           lstSalary.Add(oSalary1);
    
       }
    }
}
          


What if you want to use the same method to pass these collections and do something based on its type. Since every object in .NET inherits from System.Object, you can pass them as object type, but instead we will do something better here.

Let's create yet another class which will do something with these two objects defined above.

using System;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Web;

namespace GenericsTest
{
    public static class DataType
    {
        
        public void DoSomething<T>(List<T> lstData)
        {
           
        if (lstData.GetType() == typeof(List<Sales>))
         {

         for (int i = 0; i < lstData.Count; i++)
         {
        Sales oSale = (Sales)Convert.ChangeType(lstData[i], typeof(Sales));
        Console.WriteLine(String.Format("Sales Associate:{0},Projected Sales:{1},
        Actual Sales:{2}",oSale.SalesAssociate, oSale.Projected,oSale.Actual));                   
        Console.WriteLine(Environment.NewLine);            
         }
       }
       if (lstData.GetType() == typeof(List<Salary>))
       {

       for (int i = 0; i < lstData.Count; i++)
       {
        Salary oSalary = (Salary)Convert.ChangeType(lstData[i], typeof(Salary));
        Console.WriteLine(String.Format("Sales Associate:{0},Salary:{1},
        Commission:{2}",oSalary.SalesAssociate, 
        oSalary.BaseSalary,oSalary.Commission));              
        Console.WriteLine(Environment.NewLine);            
        }
       }
      }
    }
  }

Now all you have to do is pass either collection to this method. You can extend this method to accept collection of other types, like this...

DataType.DoSomething(lstSales);
//or
DataType.DoSomething(lstSalary);     


Generics is a very powerful concept which allows for better and more flexible code. Generics, along with reflection which we covered earlier can be a powerful tool.

Thank you.


Monday, February 20, 2012

Reflection in .NET

Reflection is the process of discovering classes, modules, assemblies or the type information of an object at run-time. Reflection works by extracting metadata information from an assembly and using this metadata to do something with it. System.Reflection namespace in .NET Framework provides the classes and interfaces that you can use to discover a class, instantiate it, discover its methods, properties and invoke them at run-time just like you would during compile time.


There are many uses of reflection, but let's demonstrate one potential use with an example.


Suppose for example, you have a sales application installed on sales associates laptops. This application allows sales associates to enter sales orders on their laptops, when they visit the clients. The application is run in offline mode but when the sales associate returns back to the office and connects to the network, the application will detect it and automatically uploads the sales orders in a centrally hosted database.


When a sales associate enters the information, a collection of the Orders object is serialized on sales associates laptop. When this laptop is connected to the company network, the application deserializes the Orders, uses reflection to type cast the object into the Orders Type and then calls the appropriate methods to save data in the database.


Let's illustrate this with an example.

//Create an Orders Class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ReflectionTest    
{
public class Orders
{
      private int _itemNumber;      
      private int _quantity;      
      private int _customerNumber;
      //properties
     
      public int ItemNumber
      { 
        get { return _itemNumber; }          
        set { _itemNumber = value; }      
      }
      public int Quantity          
      {
         get { return _quantity; }         
         set { _quantity = value; }      
      }
      public int CustomerNumber         
      {
         get { return _customerNumber; }         
         set { _customerNumber = value; }        
      }
      //constructor
     
      public Orders() 
      {}
     //Method to save data to the database
     
public void SaveToDB(List<Orders> orders)           
     {
       // do something here         
     }
  }
}

 Since we are going to serialize this object and save it on associate's laptop, let's write a class that is serializable and has a variable which stores the collection of Orders object (you can make it generic to allow for serializing and storing any object).

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
namespace  ReflectionTest 
{
    [
Serializable]    

    public class SaveObjectLocally    
    {
     //use generics so this class can be used to store any object types not just Orders
    private List<Orders> _collObjects = new List<Orders>();     

    private string _saveMethod;     
    private string _className;
    public SaveObjectLocally() { }     
    //properties
     public List<Orders> ObjectList
     {          
         get { return _collObjects; } 
         set { _collObjects = value; }     
     }
     public string SaveToDB
     {          
         get { return _saveMethod; }          
         set { _saveMethod = value; }     
     }
     public string ClassName          
     {
         get { return _className; }          
         set { _className = value; }     
     }
     //serialize
     public void Serialize(string filePath)
     {
         
Stream stream = File.Open(filePath, FileMode.Create);           

          BinaryFormatter bf = new BinaryFormatter();
          bf.Serialize(stream, this);
          stream.Close();     
     }
    //deserialize
      public SaveObjectLocally DeSerialize(string filePath)         
     {
        Stream stream = File.Open(filePath, FileMode.Open);         
        BinaryFormatter bf = new BinaryFormatter();         
        SaveObjectLocally SaveObject = (SaveObjectLocally)bf.Deserialize(stream);
        stream.Close();  
        return SaveObject; 
          }
 
    }
}

//Main Program

using System;

using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace  ReflectionTest 
{
    class Program 

    {
        
static void Main(string[] args) 
         {
              
Orders clientOrder = new Orders();
              clientOrder.ItemNumber=123;
              clientOrder.Quantity = 5;
              clientOrder.CustomerNumber=101;
              //lets assign this order to SaveObjectLocally and 

              //then save it on local machine           
             //create a list object
             
List<Orders> ordersList= new List<Orders>();
             ordersList.Add(clientOrder);
             SaveObjectLocally save = new SaveObjectLocally(); 
             save.SaveToDB = 
"SaveToDB"; 
             save.ObjectList = ordersList;


             //serialize

             save.Serialize(@"C:\Temp\Orders.xml");
                
           }
         //deserialize the saved object and upload.
         public static void UploadData() 
          {

          SaveObjectLocally save = new SaveObjectLocally(); 
          SaveObjectLocally retrieveObject = save.DeSerialize(@"C:\Temp\Orders.xml"); 
          string saveMethod = retrieveObject.SaveToDB;
          string className = retrieveObject.ClassName; 
          List<Orders> orders = retrieveObject.ObjectList;
          //now use reflection to instantiate the object
          Type ClassType = Type.GetType(className);          
          object obj = Activator.CreateInstance(ClassType);
          System.Reflection.MethodInfo callingMethod = ClassType.GetMethod(saveMethod);
          callingMethod.Invoke(obj,new Object[] {orders});
         }
         //If you have multiple objects serialized 

        //you can loop through all the files and upload one by one.
   }  
}

The example above is one use of Reflection where you can instantiate an object at run time and invoke its methods.

GetType.GetMethod and GetType.GetMethods() return you a single method or a list of methods.

Similarly, GetType.GetField() and GetType.GetFields() return you a single field or an array of all fields.

GetType.GetProperty() and GetType.GetProperties() returns property or a list of properties respectively.

You can also find out the parameters a method needs and also its return type. MethodInfo() provides information about the return type of a method and GetParameters() provides information about the parameters that a method expects.

GetConstructors() returns a list of constructors associated with this class.

Assembly Class
Assembly class is used to gather information about an assembly and manipulate the assembly. You can use it to load modules and assemblies at runtime and also search the type information within an assembly once it is loaded. Assembly class has the following methods


  • Load() - You can pass the assembly name as input parameter to search and load the assembly.
  • LoadFrom() - Takes the complete path of an assembly to search at a particular location.
  • GetExecutingAssembly() - Get the information about the currently running assembly.
  • GetTypes() - Allows you to obtain the details of all the types that are present in the assembly.
  • GetCustomAttributes() - Gets the list of custom attributes associated with this assembly. You can also pass a Type Object as a second parameter to this method to find the attributes of a specific type associated with this assembly.

As you can imagine, reflection is a very powerful feature that allows for late binding and flexibility otherwise not available during compile time. Hopefully this article will provide you enough pointers to try out reflection on your own and discover some of its additional powerful features.

Thank you and as always, your comments are welcome.

          

Friday, February 17, 2012

Generics in .NET Framework

If you came from C++ and worked on a VB 6.0 application, one thing that stood out like a sore thumb was the lack of templates. Templates in C++ allowed for type-safety and code re-usability. In VB 6.0 and in earlier versions of .NET Framework (1.0 and 1.1), you did something like this

Public Sub Add(ByVal param1 As Object, ByVal param2 As Object)

      If TypeOf(param1) = GetType(String) AND TypeOf(param2) = GetType(string) Then

              console.writeline("String=" & param1.ToString & param2.ToString)

      Else If TypeOf(param1) = GetType(int) AND TypeOf(param2) = GetType(int) Then

             console.writeline("Integer=" & DirectCast(param1,int) + DirectCast(param2,int)

      End If

End Sub

Note - C# also suffered from same limitation in 1.0 and 1.1

Aside from all the typecasting, there is something else going on here. Recall from my previous post about boxing and unboxing. If you passed integer values to this method, the passed values will be boxed and then DirectCast will unbox these values since integer is a value type.

Although this provided you flexibility in the sense that you didn't have to write two separate methods - one for numeric operation and one for string operation, it came at a performance cost.

Even if you avoided methods like these, using an arraylist with value types will result in boxing/unboxing as well (recall an example in previous post).

.NET 2.0 introduced the concept of generics. Generics allow you to define a type-safe method, class or structure without committing to a specific data type. You can write code that is just as flexible as the above example, promotes code re-use without the performance degradation of boxing / unboxing.

 Lets consider an example. Assume you want to use the flexibility of an arraylist but without its drawbacks, you can create a generic list object that framework will convert to a passed data-type during compile time.


List<int> Test = new List<int>();     //a list of type int
Test.Add(1);     //no boxing
Test.Add(2);
Test.Add("A");    //compile time error - type safe


Generic Method



void Add<T>(ref T param1)
       {
           T results;
           results = param1;
           Console.WriteLine(results);
       }


You can also declare a generic class or a structure.


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;


namespace GenericTest
{
    class GenericList<T>
    {
        void AddToList(T input) { }
    }
}



//Test Generic Class

GenericList<int> list1 = new GenericList<int>(); // list of type int
GenericList<string> list2 = new GenericList<string>(); // list of type string


As I previously mentioned, Generics allow for code re-use without compromising performance. Generics was perhaps one of the most powerful enhancement in .NET Framework 2.0.

As always, your comments are welcome.