Friday, April 25, 2014

Reflection in C#,Dynamic invoke



Reference:-Refelection 
 
C# - Attributes
An attribute is a declarative tag that is used to convey information to runtime about the behaviors of various elements like classes, methods, structures, enumerators, assemblies etc., in your program. You can add declarative information to a program by using an attribute. A declarative tag is depicted by square ([ ]) brackets placed above the element it is used for.
Attributes are used for adding metadata, such as compiler instruction and other information such as comments, description, methods and classes to a program. The .Net Framework provides two types of attributes: the pre-defined attributes and custom built attributes.

Specifying an Attribute

Syntax for specifying an attribute is as follows:
[attribute(positional_parameters, name_parameter = value, ...)]
element
Name of the attribute and its values are specified within the square brackets, before the element to which the attribute is applied. Positional parameters specify the essential information and the name parameters specify the optional information.

Predefined Attributes

The .Net Framework provides three pre-defined attributes:
·         AttributeUsage
·         Conditional
·         Obsolete

AttributeUsage:

The pre-defined attribute AttributeUsage describes how a custom attribute class can be used. It specifies the types of items to which the attribute can be applied.
Syntax for specifying this attribute is as follows:
[AttributeUsage(
   validon,
   AllowMultiple=allowmultiple,
   Inherited=inherited
)]
Where,
·         The parameter validon specifies the language elements on which the attribute can be placed. It is a combination of the value of an enumerator AttributeTargets. The default value isAttributeTargets.All.
·         The parameter allowmultiple (optional) provides value for the AllowMultiple property of this attribute, a Boolean value. If this is true, the attribute is multiuse. The default is false (single-use).
·         The parameter inherited (optional) provides value for the Inherited property of this attribute, a Boolean value. If it is true, the attribute is inherited by derived classes. The default value is false (not inherited).
For example,
[AttributeUsage(AttributeTargets.Class |
AttributeTargets.Constructor |
AttributeTargets.Feild |
AttributeTargets.Method |
AttributeTargets.Property, 
AllowMultiple = true)]

Conditional

This predefined attribute marks a conditional method whose execution depends on a specified preprocessing identifier.
It causes conditional compilation of method calls, depending on the specified value such as Debug orTrace. For example, it displays the values of the variables while debugging a code.
Syntax for specifying this attribute is as follows:
[Conditional(
   conditionalSymbol
)]
For example,
[Conditional("DEBUG")]
The following example demonstrates the attribute:
#define DEBUG
using System;
using System.Diagnostics;
public class Myclass
{
    [Conditional("DEBUG")]
    public static void Message(string msg)
    {
        Console.WriteLine(msg);
    }
}
class Test
{
    static void function1()
    {
        Myclass.Message("In Function 1.");
        function2();
    }
    static void function2()
    {
        Myclass.Message("In Function 2.");
    }
    public static void Main()
    {
        Myclass.Message("In Main function.");
        function1();
        Console.ReadKey();
    }
}
When the above code is compiled and executed, it produces the following result:
In Main function
In Function 1
In Function 2

Obsolete

This predefined attribute marks a program entity that should not be used. It enables you to inform the compiler to discard a particular target element. For example, when a new method is being used in a class, but you still want to retain the old method in the class, you may mark it as obsolete by displaying a message the new method should be used, instead of the old method.
Syntax for specifying this attribute is as follows:
[Obsolete(
   message
)]
[Obsolete(
   message,
   iserror
)]
Where,
·         The parameter message, is a string describing the reason why the item is obsolete and what to use instead.
·         The parameter iserror, is a Boolean value. If its value is true, the compiler should treat the use of the item as an error. Default value is false (compiler generates a warning).
The following program demonstrates this:
using System;
public class MyClass
{
   [Obsolete("Don't use OldMethod, use NewMethod instead", true)]
   static void OldMethod()
   { 
      Console.WriteLine("It is the old method");
   }
   static void NewMethod()
   { 
      Console.WriteLine("It is the new method"); 
   }
   public static void Main()
   {
      OldMethod();
   }
}
When you try to compile the program, the compiler gives an error message stating:
 Don't use OldMethod, use NewMethod instead

Creating Custom Attributes

The .Net Framework allows creation of custom attributes that can be used to store declarative information and can be retrieved at run-time. This information can be related to any target element depending upon the design criteria and application need.
Creating and using custom attributes involve four steps:
·         Declaring a custom attribute
·         Constructing the custom attribute
·         Apply the custom attribute on a target program element
·         Accessing Attributes Through Reflection
The Last step involves writing a simple program to read through the metadata to find various notations. Metadata is data about data or information used for describing other data. This program should use reflections for accessing attributes at runtime. This we will discuss in the next chapter.

Declaring a Custom Attribute

A new custom attribute should is derived from the System.Attribute class. For example,
//a custom attribute BugFix to be assigned to a class and its members
[AttributeUsage(AttributeTargets.Class |
AttributeTargets.Constructor |
AttributeTargets.Field |
AttributeTargets.Method |
AttributeTargets.Property,
AllowMultiple = true)]
 
public class DeBugInfo : System.Attribute
In the preceding code, we have declared a custom attribute named DeBugInfo.

Constructing the Custom Attribute

Let us construct a custom attribute named DeBugInfo, which will store the information obtained by debugging any program. Let it store the following information:
·         The code number for the bug
·         Name of the developer who identified the bug
·         Date of last review of the code
·         A string message for storing the developer's remarks
Our DeBugInfo class will have three private properties for storing the first three information and a public property for storing the message. So the bug number, developers name and date of review will be the positional parameters of the DeBugInfo class and the message will be an optional or named parameter.
Each attribute must have at least one constructor. The positional parameters should be passed through the constructor. The following code shows the DeBugInfo class:
//a custom attribute BugFix to be assigned to a class and its members
[AttributeUsage(AttributeTargets.Class |
AttributeTargets.Constructor |
AttributeTargets.Field |
AttributeTargets.Method |
AttributeTargets.Property,
AllowMultiple = true)]
 
public class DeBugInfo : System.Attribute
{
  private int bugNo;
  private string developer;
  private string lastReview;
  public string message;
 
  public DeBugInfo(int bg, string dev, string d)
  {
      this.bugNo = bg;
      this.developer = dev;
      this.lastReview = d;
  }
 
  public int BugNo
  {
      get
      {
          return bugNo;
      }
  }
  public string Developer
  {
      get
      {
          return developer;
      }
  }
  public string LastReview
  {
      get
      {
          return lastReview;
      }
  }
  public string Message
  {
      get
      {
          return message;
      }
      set
      {
          message = value;
      }
  }
}

Applying the Custom Attribute

The attribute is applied by placing it immediately before its target:
[DeBugInfo(45, "Zara Ali", "12/8/2012", Message = "Return type mismatch")]
[DeBugInfo(49, "Nuha Ali", "10/10/2012", Message = "Unused variable")]
class Rectangle
{
  //member variables
  protected double length;
  protected double width;
  public Rectangle(double l, double w)
  {
      length = l;
      width = w;
  }
  [DeBugInfo(55, "Zara Ali", "19/10/2012",
  Message = "Return type mismatch")]
  public double GetArea()
  {
      return length * width;
  }
  [DeBugInfo(56, "Zara Ali", "19/10/2012")]
  public void Display()
  {
      Console.WriteLine("Length: {0}", length);
      Console.WriteLine("Width: {0}", width);
      Console.WriteLine("Area: {0}", GetArea());
  }
}
In the next chapter we will retrieve these attribute information using a Reflection class object.
Reflection objects are used for obtaining type information at runtime. The classes that give access to the metadata of a running program are in the System.Reflection namespace.
The System.Reflection namespace contains classes that allow you to obtain information about the application and to dynamically add types, values and objects to the application.

Uses of Reflection

Reflection has the following uses:
·         It allows view attribute information at runtime.
·         It allows examining various types in an assembly and instantiate these types.
·         It allows late binding to methods and properties
·         It allows creating new types at runtime and then performs some tasks using those types.

Viewing Metadata

We have mentioned in the preceding chapter that using reflection you can view the attribute information.
The MemberInfo object of the System.Reflection class need to be initialized for discovering the attributes asscociated with a class. To do this, you define an object of the target class, as:
System.Reflection.MemberInfo info = typeof(MyClass);
The following program demonstrates this:
using System;
 
[AttributeUsage(AttributeTargets.All)]
public class HelpAttribute : System.Attribute
{
   public readonly string Url;
 
   public string Topic  // Topic is a named parameter
   {
      get
      {
         return topic;
      }
      set
      {
 
         topic = value;
      }
   }
 
   public HelpAttribute(string url)  // url is a positional parameter
   {
      this.Url = url;
   }
 
   private string topic;
}
[HelpAttribute("Information on the class MyClass")]
class MyClass
{
}
 
namespace AttributeAppl
{
   class Program
   {
      static void Main(string[] args)
      {
         System.Reflection.MemberInfo info = typeof(MyClass);
         object[] attributes = info.GetCustomAttributes(true);
         for (int i = 0; i < attributes.Length; i++)
         {
            System.Console.WriteLine(attributes[i]);
         }
         Console.ReadKey();
 
      }
   }
}
When it is compiled and run, it displays the name of the custom attributes attached to the classMyClass:
HelpAttribute

Example

In this example, we will use the DeBugInfo attribute created in the previous chapter and use reflection to read metadata in the Rectangle class.
using System;
using System.Reflection;
namespace BugFixApplication
{
   //a custom attribute BugFix to be 
         //assigned to a class and its members
   [AttributeUsage(AttributeTargets.Class |
   AttributeTargets.Constructor |
   AttributeTargets.Field |
   AttributeTargets.Method |
   AttributeTargets.Property,
   AllowMultiple = true)]
 
   public class DeBugInfo : System.Attribute
   {
      private int bugNo;
      private string developer;
      private string lastReview;
      public string message;
 
      public DeBugInfo(int bg, string dev, string d)
      {
         this.bugNo = bg;
         this.developer = dev;
         this.lastReview = d;
      }
 
      public int BugNo
      {
         get
         {
            return bugNo;
         }
      }
      public string Developer
      {
         get
         {
            return developer;
         }
      }
      public string LastReview
      {
         get
         {
            return lastReview;
         }
      }
      public string Message
      {
         get
         {
            return message;
         }
         set
         {
            message = value;
         }
      }
   }
   [DeBugInfo(45, "Zara Ali", "12/8/2012",
         Message = "Return type mismatch")]
   [DeBugInfo(49, "Nuha Ali", "10/10/2012",
         Message = "Unused variable")]
   class Rectangle
   {
      //member variables
      protected double length;
      protected double width;
      public Rectangle(double l, double w)
      {
         length = l;
         width = w;
      }
      [DeBugInfo(55, "Zara Ali", "19/10/2012",
            Message = "Return type mismatch")]
      public double GetArea()
      {
         return length * width;
      }
      [DeBugInfo(56, "Zara Ali", "19/10/2012")]
      public void Display()
      {
         Console.WriteLine("Length: {0}", length);
         Console.WriteLine("Width: {0}", width);
         Console.WriteLine("Area: {0}", GetArea());
      }
   }//end class Rectangle  
   
   class ExecuteRectangle
   {
      static void Main(string[] args)
      {
         Rectangle r = new Rectangle(4.5, 7.5);
         r.Display();
         Type type = typeof(Rectangle);
         //iterating through the attribtues of the Rectangle class
         foreach (Object attributes in type.GetCustomAttributes(false))
         {
            DeBugInfo dbi = (DeBugInfo)attributes;
            if (null != dbi)
            {
               Console.WriteLine("Bug no: {0}", dbi.BugNo);
               Console.WriteLine("Developer: {0}", dbi.Developer);
               Console.WriteLine("Last Reviewed: {0}",
                                            dbi.LastReview);
               Console.WriteLine("Remarks: {0}", dbi.Message);
            }
         }
         
         //iterating through the method attribtues
         foreach (MethodInfo m in type.GetMethods())
         {
            foreach (Attribute a in m.GetCustomAttributes(true))
            {
               DeBugInfo dbi = (DeBugInfo)a;
               if (null != dbi)
               {
                  Console.WriteLine("Bug no: {0}, for Method: {1}",
                                                    dbi.BugNo, m.Name);
                  Console.WriteLine("Developer: {0}", dbi.Developer);
                  Console.WriteLine("Last Reviewed: {0}",
                                                    dbi.LastReview);
                  Console.WriteLine("Remarks: {0}", dbi.Message);
               }
            }
         }
         Console.ReadLine();
      }
   }
}
When the above code is compiled and executed, it produces the following result:
 http://www.codeproject.com/Articles/55710/Reflection-in-NET?display=Print

Reflection in .NET

By , 9 Feb 2010

Contents

Introduction

In this article, I have tried to cover all the topics from .NET Reflection with examples. I have stated with the definition of .NET Reflection and its road map, a list of mostly used classes theSystem.Reflection namespace provides, and the importance of the Type class in .NET Reflection. You will also learn how to get the type information using different ways. Use of properties and methods of the Type class in .NET Reflection, with examples, are explained in this article. You will also see advanced Reflection topics like dynamically loading an assembly and late binding, at the end of this article.

What is .NET Reflection?

.NET Framework's Reflection API allows you to fetch type (assembly) information at runtime programmatically. We can also achieve late binding by using .NET Reflection. At runtime, the Reflection mechanism uses the PE file to read information about the assembly. Reflection enables you to use code that is not available at compile time. .NET Reflection allows an application to collect information about itself and also to manipulate on itself. It can be used effectively to find all types in an assembly and/or dynamically invoke methods in an assembly. This includes information about the type, properties, methods, and events of an object. With Reflection, we can dynamically create an instance of a type, bind the type to an existing object, or get the type from an existing object and invoke its methods or access its fields and properties. We can also access attribute information using Reflection.
Using Reflection, you can get any kind of information which you can see in a class viewer; for example, information on the methods, properties, fields, and events of an object.
The System.Reflection namespace and the System.Type class plays a very important role in .NET Reflection. These two work together and allow you to reflect over many other aspects of a type.

Road Map

The System.Reflection Namespace

The System.Reflection namespace contains the classes and interfaces that provide a managed view of loaded types, methods, and fields, with the ability to dynamically create and invoke types; this process is known as Reflection in .NET framework. We will take a look at some of the commonly used classed here:
ClassDescription
AssemblyRepresents an assembly, which is a reusable, versionable, and self-describing building block of a Common Language Runtime application. This class contains a number of methods that allow you to load, investigate, and manipulate an assembly.
ModulePerforms Reflection on a module. This class allows you to access a given module within a multi-file assembly.
AssemblyNameThis class allows you to discover numerous details behind an assembly's identity. An assembly's identity consists of the following:
  • Simple name
  • Version number
  • Cryptographic key pair
  • Supported culture
EventInfoThis class holds information for a given event. Use the EventInfo class to inspect events and to bind to event handlers.
FieldInfoThis class holds information for a given field. Fields are variables defined in the class. FieldInfo provides access to the metadata for a field within a class, and provides dynamic set and get functionality for the field. The class is not loaded into memory until Invoke or get is called on the object.
MemberInfoThe MemberInfo class is the abstract base class for classes used to obtain information about all members of a class (constructors, events, fields, methods, and properties).
MethodInfoThis class contains information for a given method.
ParameterInfoThis class holds information for a given parameter.
PropertyInfoThis class holds information for a given property.
Before we start using Reflection, it is necessary to understand the System.Type class.
In order to continue with all the examples given in this article, I am using a Car class as an example. It will look like this:
// ICar.cs - Interface 
using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 

namespace Reflection 
{ 
    interface ICar 
    { 
        bool IsMoving(); 
    } 
}

// Car.cs - Class 
using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 

namespace Reflection 
{ 
    internal class Car 
    { 
        //public variables 
        public string Color; 

        //private variables 
        //String licensePlate; // e.g. "Californi 111 222" 
        //double maxSpeed;     // in kilometers per hour 
        //int startMiles; // Stating odometer reading 
        //int endMiles; // Ending odometer reading 
        //double gallons; // Gallons of gas used between the readings  

        //private vaiables 
        private int _speed; 

        //Speed - read-only property to return the speed 
        public int Speed 
        { 
            get { return _speed; } 
        } 

        //Accelerate - add mph to the speed 
        public void Accelerate(int accelerateBy) 
        { 
            //Adjust the speed 
            _speed += accelerateBy; 
        } 

        //IsMoving - is the car moving? 
        public bool IsMoving() 
        { 
            //Is the car's speed zero? 
            if (Speed == 0) 
            { 
                return false; 
            } 
            else 
            { 
                return true; 
            } 
        } 

        //Constructor 
        public Car() 
        { 
            //Set the default values 
            Color = "White"; 
            _speed = 0; 
        } 

        //Over loaded constructor 
        public Car(string color, int speed) 
        { 
            Color = color; 
            _speed = speed; 
        } 

        //methods 
        public double calculateMPG(int startMiles, int endMiles, double gallons) 
        { 
            return (endMiles - startMiles) / gallons; 
        }  
    }
}

// SportsCar.cs - Class 
using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 

namespace Reflection 
{ 
    internal class SportsCar : Car 
    { 
        //Constructor 
        public SportsCar() 
        { 
            //Change the default values 
            Color = "Green"; 
        } 
    }
}

The System.Type Class

The System.Type class is the main class for the .NET Reflection functionality and is the primary way to access metadata. The System.Type class is an abstract class and represents a type in the Common Type System (CLS).
It represents type declarations: class types, interface types, array types, value types, enumeration types, type parameters, generic type definitions, and open or closed constructed generic types.
Use the members of Type to get information about a type declaration, such as the constructors, methods, fields, properties, and events of a class, as well as the module and the assembly in which the class is deployed.
There are tree ways to obtain a Type reference:

Using System.Object.GetType()

This method returns a Type object that represents the type of an instance. Obviously, this approach will only work if you have compile-time knowledge of the type.
// ObjectGetTypeDemo.cs 
using System; 
namespace Reflection 
{ 
    class ObjectGetTypeDemo 
    { 
        static void Main(string[] args) 
        { 
            Car c = new Car(); 
            Type t = c.GetType(); 
            Console.WriteLine(t.FullName); 
            Console.ReadLine(); 
        } 
    } 
}

Output

Reflection.Car

Using System.Type.GetType()

Another way of getting type information in a more flexible manner is the GetType() static method of the Type class which gets the type with the specified name, performing a case-sensitive search.
Type.GetType() is an overloaded method that accepts the following parameters:
  1. fully qualified string name of the type you are interested in examining
  2. exception that should be thrown if the type cannot be found
  3. establishes the case sensitivity of the string
// TypeGetTypeDemo.cs 
using System; 
namespace Reflection 
{ 
    class TypeGetTypeDemo 
    { 
        static void Main(string[] args) 
        { 
            // Obtain type information using the static Type.GetType() method. 
            // (don't throw an exception if Car cannot be found and ignore case). 
            Type t = Type.GetType("Reflection.Car", false, true); 

            Console.WriteLine(t.FullName); 
            Console.ReadLine(); 
        } 
    } 
}

Output

Reflection.Car

Using the typeof () C# Operator

The final way to obtain type information is using the C# typeof operator. This operator takes the name of the type as a parameter.
// TypeofDemo.cs 
using System; 
namespace Reflection 
{ 
    class TypeofDemo 
    { 
        static void Main(string[] args) 
        { 
            // Get the Type using typeof. 
            Type t = typeof(Car); 
            Console.WriteLine(t.FullName); 
            Console.ReadLine(); 
        } 
    } 
}

Output

Reflection.Car

Type Properties

The System.Type class defines a number of members that can be used to examine a type's metadata, a great number of which return types from the System.Reflection namespace.
You can split the properties implemented by Type into three categories:
  1. A number of properties retrieve the strings containing various names associated with the class, as shown in the following table:
  2. PropertyReturns
    NameThe name of the data type.
    FullNameThe fully qualified name of the data type (including the namespace name).
    NamespaceThe name of the namespace in which the data type is defined.
  3. It is also possible to retrieve references to further type objects that represent related classes, as shown in the following table:
  4. PropertyReturns Type Reference Corresponding To
    BaseTypeImmediate base type of this type.
    UnderlyingSystemTypeThe type that this type maps to in the .NET runtime (recall that certain .NET base types actually map to specific predefined types recognized by IL).
  5. A number of Boolean properties indicating whether this type is, for example, a class, an enum, and so on.
  6. TypeMeaning in Life
    • IsAbstract
    • IsArray
    • IsClass
    • IsCOMObject
    • IsEnum
    • IsGenericTypeDefinition
    • IsGenericParameter
    • IsInterface
    • IsPrimitive
    • IsPublic
    • IsNestedPrivate
    • IsNestedPublic
    • IsSealed
    • IsValueType
    • IsPointer
    These properties (among others) allow you to discover a number of basic traits about the type you are referring to.
Here is the example of displaying type information using the System.Type class properties:
// TypePropertiesDemo.cs 
using System; 
using System.Text; 
using System.Reflection; 

namespace Reflection 
{ 
    class TypePropertiesDemo 
    { 
        static void Main() 
        { 
            // modify this line to retrieve details of any other data type 
            // Get name of type 
            Type t = typeof(Car); 
            GetTypeProperties(t); 
            Console.ReadLine(); 
        } 
        public static void GetTypeProperties(Type t) 
        { 
            StringBuilder OutputText = new StringBuilder(); 

            //properties retrieve the strings 
            OutputText.AppendLine("Analysis of type " + t.Name); 
            OutputText.AppendLine("Type Name: " + t.Name); 
            OutputText.AppendLine("Full Name: " + t.FullName); 
            OutputText.AppendLine("Namespace: " + t.Namespace); 

            //properties retrieve references        
            Type tBase = t.BaseType; 

            if (tBase != null) 
            { 
                OutputText.AppendLine("Base Type: " + tBase.Name); 
            } 

            Type tUnderlyingSystem = t.UnderlyingSystemType; 

            if (tUnderlyingSystem != null) 
            { 
                OutputText.AppendLine("UnderlyingSystem Type: " +
                    tUnderlyingSystem.Name); 
                //OutputText.AppendLine("UnderlyingSystem Type Assembly: " +
                //    tUnderlyingSystem.Assembly); 
            } 

            //properties retrieve boolean         
            OutputText.AppendLine("Is Abstract Class: " + t.IsAbstract); 
            OutputText.AppendLine("Is an Arry: " + t.IsArray); 
            OutputText.AppendLine("Is a Class: " + t.IsClass); 
            OutputText.AppendLine("Is a COM Object : " + t.IsCOMObject); 

            OutputText.AppendLine("\nPUBLIC MEMBERS:"); 
            MemberInfo[] Members = t.GetMembers(); 

            foreach (MemberInfo NextMember in Members) 
            { 
                OutputText.AppendLine(NextMember.DeclaringType + " " + 
                NextMember.MemberType + "  " + NextMember.Name); 
            } 
            Console.WriteLine(OutputText); 
        } 
    } 
}

Output

Analysis of type Car 
Type Name: Car 
Full Name: Reflection.Car 
Namespace: Reflection 
Base Type: Object 
UnderlyingSystem Type: Car 
Is Abstract Class: False 
Is an Arry: False 
Is a Class: True 
Is a COM Object : False

Public members

Reflection.Car Method  get_Speed 
Reflection.Car Method  Accelerate 
Reflection.Car Method  IsMoving 
Reflection.Car Method  calculateMPG 
System.Object Method  ToString 
System.Object Method  Equals 
System.Object Method  GetHashCode 
System.Object Method  GetType 
Reflection.Car Constructor  .ctor 
Reflection.Car Constructor  .ctor 
Reflection.Car Property  Speed 
Reflection.Car Field  Color

Type Methods

Most of the methods of System.Type are used to obtain details of the members of the corresponding data type - the constructors, properties, methods, events, and so on. Quite a large number of methods exist, but they all follow the same pattern.
Returned TypeMethods (the method with the plural name returns an Array)Description
ConstructorInfoGetConstructor(),GetConstructors()These methods allow you to obtain an array representing the items (interface, method, property, etc.) you are interested in. Each method returns a related array (e.g., GetFields() returns a FieldInfo array, GetMethods() returns a MethodInfo array, etc.). Be aware that each of these methods has a singular form (e.g., GetMethod(), GetProperty(), etc.) that allows you to retrieve a specific item by name, rather than an array of all related items.
EventInfoGetEvent(),GetEvents()
FieldInfoGetField(),GetFields()
InterfaceInfoGetInterface(),GetInterfaces()
MemberInfoGetMember(),GetMembers()
MethodInfoGetMethod(),GetMethods()
PropertyInfoGetProperty(),GetProperties()
 FindMembers()This method returns an array of MemberInfo types based on a search criteria.
TypeGetType()This static method returns a Type instance given a string name.
 InvokeMember()This method allows late binding to a given item.
For example, two methods retrieve details of the methods of the data type: GetMethod() and GetMethods().
Type t = typeof(Car); 
MethodInfo[] methods = t.GetMethods(); 
foreach (MethodInfo nextMethod in methods) 
{ 
                // etc. 
}

Reflecting on Methods

GetMethod() returns a reference to a System.Reflection.MethodInfo object, which contains details of a method. Searches for the public method with the specified name.
GetMethods() returns an array of such references. The difference is that GetMethods() returns details of all the methods, whereas GetMethod() returns details of just one method with a specified parameter list.
Both methods have overloads that take an extra parameter, a BindingFlags enumerated value that indicates which members should be returned - for example, whether to return public members, instance members, static members, and so on.
MethodInfo is derived from the abstract class MethodBase, which inherits MemberInfo. Thus, the properties and methods defined by all three of these classes are available for your use.
For example, the simplest overload of GetMethods() takes no parameters:
// GetMethodsDemo.cs 
using System; 
using System.Reflection; 

namespace Reflection 
{ 
    class GetMethodsDemo 
    { 
        static void Main() 
        { 
            // Get name of type 
            Type t = typeof(Car); 
            GetMethod(t); 
            GetMethods(t); 

            Console.ReadLine(); 
        } 

        // Display method names of type. 
        public static void GetMethods(Type t) 
        { 
            Console.WriteLine("***** Methods *****"); 
            MethodInfo[] mi = t.GetMethods(); 
            foreach (MethodInfo m in mi) 
                Console.WriteLine("->{0}", m.Name); 
            Console.WriteLine(""); 
        } 

        // Display method name of type. 
        public static void GetMethod(Type t) 
        { 
            Console.WriteLine("***** Method *****"); 
            //This searches for name is case-sensitive. 
            //The search includes public static and public instance methods. 
            MethodInfo mi = t.GetMethod("IsMoving"); 
            Console.WriteLine("->{0}", mi.Name); 
            Console.WriteLine(""); 
        } 
    } 
}

Output

***** Method ***** 
->IsMoving 
***** Methods ***** 

->get_Speed 
->Accelerate 
->IsMoving 
->calculateMPG 
->ToString 
->Equals 
->GetHashCode 
->GetType
Here, you are simply printing the name of the method using the MethodInfo.Name property. As you might guess, MethodInfo has many additional members that allow you to determine if the method is static, virtual, or abstract. Also, the MethodInfo type allows you to obtain the method's return value and parameter set.

A Second Form of GetMethods( )

A second form of GetMethods( ) lets you specify various flags that filter the methods that are retrieved. It has this general form:
MethodInfo[ ] GetMethods(BindingFlags flags)
This version obtains only those methods that match the criteria that you specify. BindingFlags is an enumeration. Here are several commonly used values:
ValueMeaning
DeclaredOnlyRetrieves only those methods defined by the specified class. Inherited methods are not included.
InstanceRetrieves instance methods.
NonPublicRetrieves non-public methods.
PublicRetrieves public methods.
StaticRetrieves static methods.
You can OR together two or more flags. In fact, minimally, you must include either Instance or Static with Public or NonPublic. Failure to do so will result in no methods being retrieved.
One of the main uses of the BindingFlags form of GetMethods( ) is to enable you to obtain a list of the methods defined by a class without also retrieving the inherited methods. This is especially useful for preventing the methods defined by an object from being obtained. For example, try substituting this call to GetMethods( ) into the preceding program:
// Now, only methods declared by MyClass are obtained. 

MethodInfo[] mi = t.GetMethods(BindingFlags.DeclaredOnly | 
                               BindingFlags.Instance |
                               BindingFlags.Public);

Reflecting on Fields and Properties

The behavior of Type.GetField() and Type.GetFields() is exactly similar to the above two methods, except Type.GetField() returns a reference of System.Reflection.MethodInfo andType.GetFields() returns a reference of a System.Reflection.MethodInfo array. Similarly, Type.GetProperty() and Type.GetProperties() too.
The logic to display a type's properties is similar:
// GetFieldsPropertiesDemo.cs 
using System; 
using System.Reflection; 

namespace Reflection 
{ 
    class GetFieldsPropertiesDemo 
    { 
        static void Main() 
        { 
            // Get name of type 
            Type t = typeof(Car); 
            GetFields(t); 
            GetProperties(t); 

            Console.ReadLine(); 
        } 

        // Display field names of type. 
        public static void GetFields(Type t) 
        { 
            Console.WriteLine("***** Fields *****"); 
            FieldInfo[] fi = t.GetFields(); 
            foreach (FieldInfo field in fi) 
                Console.WriteLine("->{0}", field.Name); 
            Console.WriteLine(""); 
        } 

        // Display property names of type. 
        public static void GetProperties(Type t) 
        { 
            Console.WriteLine("***** Properties *****"); 
            PropertyInfo[] pi = t.GetProperties(); 
            foreach (PropertyInfo prop in pi) 
                Console.WriteLine("->{0}", prop.Name); 
            Console.WriteLine(""); 
        } 
    }
}

Output

***** Fields ***** 
->Color 
***** Properties ***** 
->Speed

Reflecting on Implemented Interfaces

GetInterfaces() returns an array of System.Types! This should make sense given that interfaces are, indeed, types:
// GetInterfacesDemo.cs 
using System; 
using System.Reflection; 

namespace Reflection 
{ 
    class GetInterfacesDemo 
    { 
        static void Main() 
        { 
            // Get name of type 
            Type t = typeof(Car); 
            GetInterfaces(t); 

            Console.ReadLine(); 
        } 

        // Display implemented interfaces. 
        public static void GetInterfaces(Type t) 
        { 
            Console.WriteLine("***** Interfaces *****"); 
            Type[] ifaces = t.GetInterfaces(); 
            foreach (Type i in ifaces) 
                Console.WriteLine("->{0}", i.Name); 
        } 
    } 
}

Output

***** Interfaces ***** 
->ICar

Reflecting on Method Parameters and Return Values

To play with method parameters and return types, we first need to build a MethodInfo[] array using the GetMethods() function.
The MethodInfo type provides the ReturnType property and the GetParameters() method for these very tasks.
using System; 
using System.Reflection; 
using System.Text; 

namespace Reflection 
{ 
    class GetParameterInfoDemo 
    { 
        static void Main() 
        { 
            // Get name of type 
            Type t = typeof(Car); 
            GetParametersInfo(t); 

            Console.ReadLine(); 
        } 

        //Display Method return Type and paralmeters list 
        public static void GetParametersInfo(Type t) 
        { 
            Console.WriteLine("***** GetParametersInfo *****"); 
            MethodInfo[] mi = t.GetMethods(); 
            foreach (MethodInfo m in mi) 
            { 
                // Get return value. 
                string retVal = m.ReturnType.FullName; 
                StringBuilder paramInfo = new StringBuilder(); 
                paramInfo.Append("("); 

                // Get params. 
                foreach (ParameterInfo pi in m.GetParameters()) 
                { 
                    paramInfo.Append(string.Format("{0} {1} ", pi.ParameterType,
                        pi.Name)); 
                } 
                paramInfo.Append(")"); 

                // Now display the basic method sig. 
                Console.WriteLine("->{0} {1} {2}", retVal, m.Name, paramInfo); 
            } 
            Console.WriteLine(""); 
        } 
    } 
}

Output

***** GetParametersInfo ***** 
->System.Int32 get_Speed () 
->System.Void Accelerate (System.Int32 accelerateBy ) 
->System.Boolean IsMoving () 
->System.Double calculateMPG (System.Int32 startMiles System.Int32 endMiles Syst 
em.Double gallons ) 
->System.String ToString () 
->System.Boolean Equals (System.Object obj ) 
->System.Int32 GetHashCode () 
->System.Type GetType ()

Reflecting on Constructor

The GetConstractors() function returns an array of ConstractorInfo elements which we can use to get more class constructor information.
// GetConstractorInfoDemo.cs 
using System; 
using System.Reflection; 

namespace Reflection 
{ 
    class GetConstractorInfoDemo 
    { 
        static void Main() 
        { 
            // Get name of type 
            Type t = typeof(Car); 
            GetConstructorsInfo(t); 

            Console.ReadLine(); 
        } 

        // Display method names of type. 
        public static void GetConstructorsInfo(Type t) 
        { 
            Console.WriteLine("***** ConstructorsInfo *****"); 
            ConstructorInfo[] ci = t.GetConstructors (); 
            foreach (ConstructorInfo  c in ci) 
                Console.WriteLine(c.ToString () ); 
            Console.WriteLine(""); 
        } 
    } 
}

Output

***** ConstructorsInfo ***** 
Void .ctor() 
Void .ctor(System.String, Int32)

Assembly Class

The System.Reflection namespace provides a class called Assembly. We can use this Assembly class to fetch information about the assembly and manipulate the provided assembly; this class allows us to load modules and assemblies at run time. The Assembly class contacts the PE file to fetch the metadata information about the assembly at runtime. Once we load the assembly using this Assemblyclass, we can search the type information within the assembly. It is also possible to create instances of types returned by the Assembly class.

Dynamically Loading an Assembly

The Assembly class provides the following methods to load an assembly at runtime:
  • Load(): This static overloaded method takes the assembly name as input parameter and searches the given assembly name in the system.
  • LoadFrom(): This static overloaded method takes the complete path of an assembly, it will directly look into that particular location instead of searching in the system.
  • GetExecutingAssembly(): The Assembly class also provides another method to obtain the currently running assembly information using the GetExecutingAssembly() methods. This method is not overloaded.
  • GetTypes(): The Assembly class also provides a nice feature called the GetTypes method which allows you to obtain the details of all the types that are defined in the corresponding assembly.
  • GetCustomAttributes(): This static overloaded method gets the attributes attached to the assembly. You can also call GetCustomAttributes(), specifying a second parameter, which is aType object that indicates the attribute class in which you are interested.
// AssemblyDemo.cs 
class AssemblyDemo 
{ 
    static void Main() 
    { 
        Assembly objAssembly; 

        // You must supply a valid fully qualified assembly name here.
        objAssembly = Assembly.Load("mscorlib,2.0.0.0,Neutral,b77a5c561934e089"); 

        // Loads an assembly using its file name   
        //objAssembly = Assembly.LoadFrom(
        //    @"C:\Windows\Microsoft.NET\Framework\v1.1.4322\caspol.exe"); 

        //this loads currnly running process assembly 
        // objAssembly = Assembly.GetExecutingAssembly(); 

        Type[] Types = objAssembly.GetTypes(); 

        // Display all the types contained in the specified assembly. 
        foreach (Type objType in Types) 
        { 
            Console.WriteLine(objType.Name.ToString()); 
        } 

        //fetching custom attributes within an assembly 
        Attribute[] arrayAttributes = 
        Attribute.GetCustomAttributes(objAssembly); 

        // assembly1 is an Assembly object 
        foreach (Attribute attrib in arrayAttributes) 
        { 
            Console.WriteLine(attrib.TypeId ); 
        } 

        Console.ReadLine(); 
    }
}

Late Binding

Late binding is a powerful technology in .NET Reflection which allows you to create an instance of a given type and invoke its members at runtime without having compile-time knowledge of its existence; this technique is also called dynamic invocation. This technique is useful only when working with an object which is not available at compile time. In this technique, it is the developer's responsibility to pass the correct signature of the methods before invoking; otherwise, it will throw an error, whereas in early binding, the compiler verifies the method signature before calling the method. It is very important to take the right decision when to call and use and when not to use this because of performance issues. Using this technique has an impact on the performance of your application.
// LateBindingDemo.cs 
using System; 
using System.Reflection; 

namespace Reflection 
{ 
    class LateBindingDemo 
    { 
        static void Main() 
        { 
            Assembly objAssembly; 
            // Loads an assembly  
            objAssembly = Assembly.GetExecutingAssembly(); 

            //get the class type information in which late bindig applied 
            Type classType = objAssembly.GetType("Reflection.Car");

            //create the instance of class using System.Activator class 
            object  obj  =  Activator.CreateInstance(classType); 

            //get the method information 
            MethodInfo mi = classType.GetMethod("IsMoving"); 

            //Late Binding using Invoke method without parameters 
            bool isCarMoving; 
            isCarMoving= (bool) mi.Invoke(obj, null); 
            if (isCarMoving) 
            { 
                Console.WriteLine("Car Moving Status is : Moving"); 
            } 
            else 
            { 
                Console.WriteLine("Car Moving Status is : Not Moving"); 
            } 

            //Late Binding with parameters 
            object[] parameters = new object[3]; 
            parameters[0] = 32456;//parameter 1 startMiles 
            parameters[1] = 32810;//parameter 2 end Miles 
            parameters[2] = 10.6;//parameter 3 gallons 
            mi = classType.GetMethod("calculateMPG"); 
            double MilesPerGallon; 
            MilesPerGallon= (double ) mi.Invoke(obj, parameters); 
            Console.WriteLine("Miles per gallon is : " + MilesPerGallon); 

            Console.ReadLine(); 
        } 
    } 
}

Output

Car Moving Status is : Not Moving 
Miles per gallon is : 33.3962264150943

Reflection Emit

Reflection emit supports dynamic creation of new types at runtime. You can define an assembly to run dynamically or to save itself to disk, and you can define modules and new types with methods that you can then invoke.

Conclusion

Reflection in .NET is huge. Covering an entire API is not possible in this article. However, learning one part of it will give you a complete understanding of Reflection in .NET.
Thanks for reading my article. I hope you enjoyed it very much.























Length: 4.5
Width: 7.5
Area: 33.75
Bug No: 49
Developer: Nuha Ali
Last Reviewed: 10/10/2012
Remarks: Unused variable
Bug No: 45
Developer: Zara Ali
Last Reviewed: 12/8/2012
Remarks: Return type mismatch
Bug No: 55, for Method: GetArea
Developer: Zara Ali
Last Reviewed: 19/10/2012
Remarks: Return type mismatch
Bug No: 56, for Method: Display
Developer: Zara Ali
Last Reviewed: 19/10/2012
Remarks: 
  
 

No comments:

Post a Comment