Click here to Skip to main content
15,893,594 members
Articles / Programming Languages / C#

.Net Expression Evaluator using DynamicMethod

Rate me:
Please Sign up or sign in to vote.
4.97/5 (23 votes)
13 Mar 20076 min read 120.5K   2.1K   102  
Evaluating Dynamic expressions by compiling C# code to IL, then creating a DynamicMethod from the IL.
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Reflection.Emit;

namespace ExpressionEval.MsilConversion
{
    /// <summary>
    /// Resolves tokens for given code bytes and a DynamicILInfo
    /// </summary>
    public class IlTokenResolver
    {
        private IDictionary<int, RuntimeFieldHandle> m_fields;
        private IDictionary<int, MethodBase> m_methods;
        private IDictionary<int, RuntimeTypeHandle> m_types;
        private IDictionary<int, string> m_literalStrings;

        /// <summary>
        /// Constructor that takes all the tokens to resolve
        /// </summary>
        /// <param name="fields"></param>
        /// <param name="methods"></param>
        /// <param name="types"></param>
        /// <param name="literalStrings"></param>
        public IlTokenResolver(IDictionary<int, RuntimeFieldHandle> fields, IDictionary<int, MethodBase> methods, IDictionary<int, RuntimeTypeHandle> types, IDictionary<int, string> literalStrings)
        {
            m_fields = fields;
            m_methods = methods;
            m_types = types;
            m_literalStrings = literalStrings;

        }

        /// <summary>
        /// Resolves the tokens given the code bytes and DynamicILInfo class
        /// </summary>
        /// <param name="code"></param>
        /// <param name="dynamicInfo"></param>
        /// <returns>byte[] - code bytes with resolved tokens</returns>
        public byte[] ResolveCodeTokens(byte[] code, DynamicILInfo dynamicInfo)
        {
            byte[] resolvedCode = new byte[code.Length];

            //copy code bytes
            Array.Copy(code, resolvedCode, code.Length);

            //resolve fields
            foreach (int offset in m_fields.Keys)
            {
                int newMetadataToken = dynamicInfo.GetTokenFor(m_fields[offset]);

                OverwriteInt32(resolvedCode, offset, newMetadataToken);
            }

            //resolve methods
            foreach (int offset in m_methods.Keys)
            {
                int newMetadataToken;
                MethodBase methodBase;

                methodBase = m_methods[offset];
                
                //generic types require the declaring type when resolving
                if (methodBase.DeclaringType != null && methodBase.DeclaringType.IsGenericType)
                {
                    newMetadataToken = dynamicInfo.GetTokenFor(methodBase.MethodHandle, methodBase.DeclaringType.TypeHandle);
                }
                else
                {
                    newMetadataToken = dynamicInfo.GetTokenFor(methodBase.MethodHandle);
                }

                OverwriteInt32(resolvedCode, offset, newMetadataToken);
            }

            //resolve types
            foreach (int offset in m_types.Keys)
            {
                int newMetadataToken = dynamicInfo.GetTokenFor(m_types[offset]);

                OverwriteInt32(resolvedCode, offset, newMetadataToken);
            }

            //resolve strings
            foreach (int offset in m_literalStrings.Keys)
            {
                int newMetadataToken = dynamicInfo.GetTokenFor(m_literalStrings[offset]);

                OverwriteInt32(resolvedCode, offset, newMetadataToken);
            }

            return resolvedCode;
        }

        /// <summary>
        /// Method to overwrite an int value with another within code bytes.
        /// </summary>
        /// <param name="code">code bytes</param>
        /// <param name="offset">byte index</param>
        /// <param name="tokenValue">value to write</param>
        private void OverwriteInt32(byte[] code, int offset, int tokenValue)
        {
            code[offset++] = (byte)tokenValue;
            code[offset++] = (byte)(tokenValue >> 8);
            code[offset++] = (byte)(tokenValue >> 16);
            code[offset] = (byte)(tokenValue >> 24);
        }
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
United States United States
.Net Software Engineer in Kansas, USA trying to keep pace with technology.

Comments and Discussions