Click here to Skip to main content
15,881,812 members
Articles / Programming Languages / C#
Article

Perform Reflection and XML Traversing Using the dynamic Keyword in C#

Rate me:
Please Sign up or sign in to vote.
4.83/5 (13 votes)
5 May 2011CPOL10 min read 34.5K   375   39   11
Demonstrates using the dynamic keyword in Reflection and XML traversing.

Introduction (How to use the dynamic keyword)

The dynamic keyword is a new feature in C# 4.0. A dynamic object's type may not be known until runtime and that means the members of that dynamic object and the signatures will not be known at runtime. It also means that the calls to the methods of that dynamic object will be dispatched dynamically. When we say dynamically dispatched, it may fail if it does not find a given method at run time. It bypasses the compile time type checking and dynamic operations will be resolved at runtime.

The implementation of the dynamic keyword happens using the component DLR (Dynamic Language Runtime).

How to use

Image 1

We use the keyword dynamic to create dynamic object and use it like any other type.

  • In the above figure, here is how we are using the dynamic keyword:
    • Make the return type of the method as dynamic.
    • Pass parameter of dynamic type in place of a variable of integer type.
    • Declare a variable of dynamic type where the value is a string.
    • Declare a variable of dynamic type where the value is a float.
    • Declare a variable of dynamic type where the value is a reference type.

Compiler behavior

A dynamic type bypasses compile time type checking. At compile time, it records the metadata about the various calls such as what it means, and the types of parameters passed in. The metadata can be used during run time to resolve the call, and one of two things is going to happen: it gets dynamically dispatched or it generates a run time error.

Compile time members of a dynamic type variable

Image 2

As the above code (underlined in red) says, we try to access the members of a dynamic type variable named “dynamicVariableInt” and it shows that “This operation will be resolved at runtime”.

Now you might ask, what happens if I forcefully give the member names. Refer to the below code and read the comments to see what happens when we forcefully give the member names.

Image 3

Dynamic objects get resolved at run time, and the second last statement in the above code does not generate a compile time error because the whole operation will be resolved at run time. It throws an error (run time binder exception) at run time.

At run time, it looks for member names implemented and does much more with the classes of the System.Core -> System.Dynamic namespace.

Limitations

  • Dynamic look up can’t resolve extension methods
  • Dynamic method call can’t pass anonymous functions
  • Can’t use LINQ over dynamic objects

DLR (Dynamic Language Runtime)

  • All the operations happen under dynamic lookup based on component DLR
  • It is a normal assembly hosted on CLR (System.Core)
  • Uses lightweight code gen part of the System.Reflection namespace

2. DynamicObject class

Use the System.Dynamic namespace for making a class available. It allows a base class for specifying dynamic behavior at run time. This class must be inherited from another, and we cannot instantiate it directly. This class allows us to define operations that can be performed on dynamic objects. For example, when we try to get the member of any defined class and if that member is not available, then we can define the operations to be performed at the time of unavailability of members. Further, we have to use syntax like obj.SetPeroperty (“IsActive”, “True”) to set the property name IsActive. Instead, we can write this: obj.IsActive = True. To enable dynamic behavior for an instance of a class derived from the DynamicObject class, we must use the dynamic keyword as explained in the Introduction section.

How to use

Image 4

The SampleDynamicObjectClass class will allow us to perform dynamic operations by inheriting the DynamicObject class and by using the methods of the DynamicObject class. The DynamicObject class offers many methods to be overridden in the inheriting class and we will see two of those methods: TryInvokeMember and TrySetMember.

In the above example, we have created a class SampleDynamicObjectClass which inherits the DynamicObject class. Now we will use the TryInvokeMember and TryGetMember methods of the DynamicObject class by overriding the SampleDynamicObject class.

The main method creates a new object of type SampleDynamicObjectClass and assigns it to the dynamic object type so that it can call a member dynamically at run time.

TryInvokeMember()

When we call the sampleObj.SampleMethod () method, we are calling a method which is not available in the current class and we are calling it so it will go to the TryInvokemember method and set binder.Name to the member name which was called, in our case, we have SampleMethod (), and we can also pass arguments in the methods which will reflect in the args [] array of the TryinvokeMember () method.

The TryInvokeMember() method will be called when we try to call a method of the SampleDynamicObjectClass class, which is not available in this class and so we need to perform dynamic operations here (missing method). So, we provide the implementation for operations that invoke a member so this class can override this method to specify dynamic behavior for operations such as calling a method. The Binder parameter provides information about dynamic operations, binder.Name provides the name of the member on which the dynamic operation is performed.

For example: sampleObj.SampleMethod ("True"), where sampleObj is an instance of this class. Here, binder.Name returns SampleMethod.

The result will hold the result of the member invocation.

The return type will hold true if the operations are successful and if this method returns false, the run time binder of the language determines the behavior (most of the time, a language specific run time exception is thrown).

TryGetMember()

When we say sampleObj.SampleProperty, it means we are calling a property which is not available in the current class and we are calling it, so it will go to the TryGetMember method and set binder.Name to the member name which was called; in our case, we have SampleProperty.

The TryGetMember method will be called when we try to use a property of the SampleDynamicObjectClass class which is not available and needs to perform dynamic operations. We provide the implementation for operations that get a member so this class can override this method to specify dynamic behavior for operations such as accessing a property. The Binder parameter provides information about dynamic operations; binder.Name provides the name of the member on which the dynamic operation is performed.

For example: sampleObj.SampleProperty;, where sampleObj is an instance of this class. Here, binder.Name returns SampleProperty.

The result will hold the result of member invocation. The return type will hold true if the operation is successful, and if this method returns false, the run time binder of the language determines the behavior (most of the time, a run time exception is thrown).

The above explained concept will be used in real time applications as shown below.

3. XmlTraversing using dynamic

Introduction

Based on the above DynamicObject class concepts explained, we will create an application for XML traversing. It will give an idea of how to use the TryGetMember method of the DynamicObject class which is necessary to understand the XmlTraversing application.

Firstly, manipulating XElements can be done with methods of the XElement object and the syntax is:

C#
// Creates an XElement dynamically
XElement xmlNavigation = XElement.Parse(@"
                            <Emails>
                                <Email>
                                    <Id>1</Id>
                                    <Description>sanjay.patolia@gmail.com</Description>
                                </Email>
                                <Email>
                                    <Id>2</Id>
                                    <Description>sanjay.patolia@patni.com</Description>
                                </Email>
                            </Emails>
                            ");

var email = xmlNavigation.Elements("Email");

In the above example, to fetch all the "Email" elements, we use the Elements ("Emails") statement. In the same way, we use other methods to manipulate other XML reading operations. Here, our work has been done for fetching elements, but it does not come in easily readable format. We can achieve that kind of functionality using the DynamicObject class and a dynamic keyword, which allows us to navigate through the XML in easily readable format. We just need to keep track of XmlStructure.

Let's talk a bit about the DynamicObject class.

The DynamicObject class allows us to implement operations dynamically, when we try to get member values or set member values. Here we will look at the TryGetMember method of the DynamicObject class which will be called when we will try to get the values of properties which are not implemented in the class.

Let us see an example of XML navigation using the DynamincObject class and the dynamic keyword.

C#
namespace XmlNavigationUsingDynamic
{
    class Program
    {
        static void Main(string[] args)
        {
            // Creates an XML file in memory
            dynamic xmlNavigation = new XmlNavigationUsingDynamic
                (XElement.Parse(@"
                            <Emails>
                                <Email>
                                    <Id>1</Id>
                                    <Description>sanjay.patolia@gmail.com</Description>
                                </Email>
                                <Email>
                                   <Id>2</Id>
                                   <Description>sanjay.patolia@patni.com</Description>
                                </Email>
                            </Emails>
                            "));
 
            // Taking collection of "Description" elements into IEnumerable<XElement>
            // Here, we can also take it into var type instead of IEnumerable<XElement>
            IEnumerable<XElement> descriptionNodes = xmlNavigation.Email.Description;
 
            // Printing an elements "Description"
            descriptionNodes.ToList().ForEach(emailDesc =>
            {
                Console.WriteLine(emailDesc);
            });
 
            Console.ReadKey(true);
        }
    }
 
    /// <summary>
    /// XmlNavigationUsingDynamic class
    /// This allows us to perform dynamic operations
    /// </summary>
    public class XmlNavigationUsingDynamic : DynamicObject, IEnumerable<XElement>
    { 
        /// <summary>
        /// Xml node to be crated
        /// </summary>
        IEnumerable<XElement> node = null;
 
        /// <summary>
        /// Initializes node member
        /// </summary>
        /// <param name="nodes">XElements parameters</param>
        public XmlNavigationUsingDynamic(params XElement[] nodes)
        {
            node = nodes;
        }
 
        /// <summary>
        /// Allows to implement code for dynamic operations
        /// will be called when we try to Get any member of this class
        /// </summary>
        /// <param name="binder">Here we are using this to fetch 
        /// name of the member which is being called</param>
        /// <param name="result">Allows to assign a value to a property 
        /// which is being called
        /// For example: 
        /// When we say, 
        ///         xmlNavigation.Email, it will call this method with 
        ///         name in binder object and 
        ///         when we set result object that will be returned to the caller
        /// </param>
        /// <returns>true or false to say whether it was successful or not</returns>
        public override bool TryGetMember(GetMemberBinder binder, out object result)
        {
            var genericNode = node.Elements(binder.Name).ToArray();
            result = new XmlNavigationUsingDynamic(genericNode);
            return true;
        }
 
        /// <summary>
        /// Gets enumerator
        /// </summary>
        /// <returns></returns>
        public IEnumerator<XElement> GetEnumerator()
        {
            return node.GetEnumerator();
        }
 
        /// <summary>
        /// Calls GetEnumerator method
        /// </summary>
        /// <returns>IEnumerator</returns>
        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
    }
}

In the above example:

C#
// Creates an Xml file in memory

dynamic xmlNavigation = new XmlNavigationUsingDynamic
         (XElement.Parse(@"
                        <Emails>
                            <Email>
                                <Id>1</Id>
                                <Description>sanjay.patolia@gmail.com</Description>
                            </Email>
                            <Email>
                                <Id>2</Id>
                                <Description>sanjay.patolia@patni.com</Description>
                            </Email>
                        </Emails>
                        "));

creates an XML file in memory.

C#
xmlNavigation.Email

xmlNavigation is an object of the XmlNavigationUsingDynamic class and Email is a member of that class. We are trying to access a member of that class. This statement will call the TryGetMember method; it performs an operation and sets the result object which will be the base of "Description", because the result object is set to an object of the XmlNavigationUsingDynamic class.

C#
xmlNavigation.Email.Description

Description will be called from the result (object set from the TryGetMember method) and returns IEnumerable<XElement> because we have implemented IEnumerable<XElement>, and the node.GetEnumerator() method is called which is implemented from the IEnumerable interface and returns IEnumerable<XElement> and we iterate it to get the element "Description".

Here we can see the difference in traversing the XML file:

C#
// Using typical XML traversing using XElements.
var email = xmlNavigation.Elements("Email");
 
// Using DynamicObject class XML traversing.
// We can use var here as required.
IEnumerable<XElement> descriptionNodes = xmlNavigation.Email.Description;

In this way we can perform other XML navigation operations too.

Performance

Use of dynamic in XML navigation or manipulating XML in other ways provides easy readability and simplicity but will have a bit of performance hit.

4. Reflection using dynamic

Introduction

Wherever we find .GetProperties () or .GetType () in code, we can go for dynamic with a lower cost in performance.

Reflection is all about manipulating data based on metadata. Reflection provides objects that wrap assemblies, modules, and types. We can use Reflection to dynamically create an instance of a type, bind the type to an existing object, and invoke its methods or access its fields and properties.

Let’s take a tiny example of Reflection.

C#
// Use GetType () to fetch type information
int i = 4;
System.Type type = i.GetType ();
Console.WriteLine (type);

Output is: System.Int32.

Let’s take another example of Reflection:

C#
// using Reflection to get information from an Assembly:
System.Reflection.Assembly obj = 
   System.Reflection.Assembly.Load ("Sample.dll");
System.Console.WriteLine (obj.GetName ());

In the same way, we can create an instance at run time based on a specified type. And then we can call the methods, and access properties of that type using the instance object.

For example:

C#
// Using Reflection to get information from an Assembly:
Assembly obj = System.Reflection.Assembly.Load("Sample.dll");
obj.GetTypes().ToList().ForEach(type =>
    {
                 object objInstance = Activator.CreateInstance(type);
        MethodInfo methodInfo = type.GetMethod("Display");
        methodInfo.Invoke(objInstance, null);
    });

In the above example, let’s assume that the Sample.dll assembly has only one class named “Sample” and only one method in it named “Display”. We have loaded the assembly dynamically, iterated all the types under that assembly, created an instance of all the types using Activator, and tried to call a member of a type where the member can be a property or a method.

In the above example, we use the MethodInfo class to get a method name and then call the method using the Invoke method of the MethodInfo class, providing the object instance and parameters in the argument of the Invoke method to call the method Display.

The same behavior with a lower cost can be achieved using dynamic.

The first statement in the lambda expression creates an instance of object type and we can not call any member of the object type because we don’t know the type here. Why don’t we set that instance type as a dynamic type so that we can call its members at run time?

For example:

C#
// Using Reflection to get information from an Assembly:
Assembly obj = System.Reflection.Assembly.Load("Sample.dll");
obj.GetTypes().ToList().ForEach(type =>
    {
        dynamic objInstance = Activator.CreateInstance(type);
        objInstance.Display();
    });

Now, we compare the above two examples, with dynamic and without dynamic. We will find a major difference in code because we are not using MethodInfo and all. This way, we can filter other classes used in Reflection too.

We can call any member of a dynamic type at run time. We will call a method directly without needing any further logic, such as MethoInfo. It is a pretty simple and cost saving concept to use dynamic in place of Reflection.

Performance

Use of dynamic in Reflection achieves better performance in comparison of typical Reflection techniques.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer Software Industry
India India
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralMy vote of 5 Pin
Halil ibrahim Kalkan5-May-11 22:36
Halil ibrahim Kalkan5-May-11 22:36 
GeneralRe: My vote of 5 Pin
Sanjay J Patolia5-May-11 23:03
Sanjay J Patolia5-May-11 23:03 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.