views:

354

answers:

2

I want to learn dynamic method and its practical example using c#. Is there any relation between dynamic method and Reflection? Please help me.

+1  A: 

You can create a method via DynamicMethod class.

DynamicMethod squareIt = new DynamicMethod(
    "SquareIt", 
    typeof(long), 
    methodArgs, 
    typeof(Example).Module);

ILGenerator il = squareIt.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Conv_I8);
il.Emit(OpCodes.Dup);
il.Emit(OpCodes.Mul);
il.Emit(OpCodes.Ret);

Fully commented example is here: http://msdn.microsoft.com/en-us/library/exczf7b9.aspx I should note that this method is very slow and not very useful.

VMAtm
Pankaj
I mean the development speed - it isn't very fast and very hard to maintain such code.
VMAtm
ILGenerator - is a part of System.Reflection.EmitIn somewhat it is a relation between Reflection and dynamic methods
VMAtm
A: 

We are using Dynamic methods for speed up Reflection. Here is code of our reflection optimizer. it is only 10% slower than direct call and 2000 times faster that reflection call

public class ReflectionEmitPropertyAccessor
    {
     private readonly bool canRead;
     private readonly bool canWrite;
     private IPropertyAccessor emittedPropertyAccessor;
     private readonly string propertyName;
     private readonly Type propertyType;
     private readonly Type targetType;
     private Dictionary<Type,OpCode> typeOpCodes;

     public ReflectionEmitPropertyAccessor(Type targetType, string property)
     {
      this.targetType = targetType;
      propertyName = property;
            var propertyInfo = targetType.GetProperty(property);
      if (propertyInfo == null)
      {
       throw new ReflectionOptimizerException(string.Format("Property \"{0}\" is not found in type "+ "{1}.", property, targetType));
      }
      canRead = propertyInfo.CanRead;
      canWrite = propertyInfo.CanWrite;
      propertyType = propertyInfo.PropertyType;
     }

     public bool CanRead
     {
      get { return canRead; }
     }

     public bool CanWrite
     {
      get { return canWrite; }
     }

     public Type TargetType
     {
      get { return targetType; }
     }

     public Type PropertyType
     {
      get { return propertyType; }
     }

     #region IPropertyAccessor Members

     public object Get(object target)
     {
      if (canRead)
      {
       if (emittedPropertyAccessor == null)
       {
        Init();
       }

       if (emittedPropertyAccessor != null) return emittedPropertyAccessor.Get(target);

      }
      else
      {
       throw new ReflectionOptimizerException(string.Format("У свойства \"{0}\" нет метода get.", propertyName));
      }
      throw new ReflectionOptimizerException("Fail initialize of " + GetType().FullName);
     }

     public void Set(object target, object value)
     {
      if (canWrite)
      {
       if (emittedPropertyAccessor == null)
       {
        Init();
       }
       if (emittedPropertyAccessor != null) emittedPropertyAccessor.Set(target, value);
      }
      else
      {
       throw new ReflectionOptimizerException(string.Format("Property \"{0}\" does not have method set.", propertyName));
      }
      throw new ReflectionOptimizerException("Fail initialize of " + GetType().FullName);
     }

     #endregion

     private void Init()
     {
      InitTypeOpCodes();
      var assembly = EmitAssembly();
      emittedPropertyAccessor = assembly.CreateInstance("Property") as IPropertyAccessor;
            if (emittedPropertyAccessor == null)
      {
       throw new ReflectionOptimizerException("Shit happense in PropertyAccessor.");
      }
     }

     private void InitTypeOpCodes()
     {
      typeOpCodes = new Dictionary<Type, OpCode>
                     {
                      {typeof (sbyte), OpCodes.Ldind_I1},
                      {typeof (byte), OpCodes.Ldind_U1},
                      {typeof (char), OpCodes.Ldind_U2},
                      {typeof (short), OpCodes.Ldind_I2},
                      {typeof (ushort), OpCodes.Ldind_U2},
                      {typeof (int), OpCodes.Ldind_I4},
                      {typeof (uint), OpCodes.Ldind_U4},
                      {typeof (long), OpCodes.Ldind_I8},
                      {typeof (ulong), OpCodes.Ldind_I8},
                      {typeof (bool), OpCodes.Ldind_I1},
                      {typeof (double), OpCodes.Ldind_R8},
                      {typeof (float), OpCodes.Ldind_R4}
                     };
     }

     private Assembly EmitAssembly()
     {
      var assemblyName = new AssemblyName {Name = "PropertyAccessorAssembly"};
      var newAssembly = Thread.GetDomain().DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
      var newModule = newAssembly.DefineDynamicModule("Module");
      var dynamicType = newModule.DefineType("Property", TypeAttributes.Public);
            dynamicType.AddInterfaceImplementation(typeof(IPropertyAccessor));
            dynamicType.DefineDefaultConstructor(MethodAttributes.Public);
      var getParamTypes = new[] { typeof(object) };
      var getReturnType = typeof(object);
      var getMethod = dynamicType.DefineMethod("Get",
            MethodAttributes.Public | MethodAttributes.Virtual,
            getReturnType,
            getParamTypes);

      var getIL = getMethod.GetILGenerator();
            var targetGetMethod = targetType.GetMethod("get_" + propertyName);

      if (targetGetMethod != null)
      {
       getIL.DeclareLocal(typeof(object));
       getIL.Emit(OpCodes.Ldarg_1); //Load the first argument 
       getIL.Emit(OpCodes.Castclass, targetType); //Cast to the source type
                getIL.EmitCall(OpCodes.Call, targetGetMethod, null); //Get the property value
                if (targetGetMethod.ReturnType.IsValueType)
       {
        getIL.Emit(OpCodes.Box, targetGetMethod.ReturnType); //Box
       }
       getIL.Emit(OpCodes.Stloc_0); //Store it
                getIL.Emit(OpCodes.Ldloc_0);
      }
      else
      {
       getIL.ThrowException(typeof(MissingMethodException));
      }

      getIL.Emit(OpCodes.Ret);
      var setParamTypes = new[] { typeof(object), typeof(object) };
      const Type setReturnType = null;
      var setMethod = dynamicType.DefineMethod("Set",
            MethodAttributes.Public | MethodAttributes.Virtual,
            setReturnType,
            setParamTypes);

      var setIL = setMethod.GetILGenerator();

      var targetSetMethod = targetType.GetMethod("set_" + propertyName);
      if (targetSetMethod != null)
      {
       Type paramType = targetSetMethod.GetParameters()[0].ParameterType;

       setIL.DeclareLocal(paramType);
       setIL.Emit(OpCodes.Ldarg_1); //Load the first argument //(target object)
                setIL.Emit(OpCodes.Castclass, targetType); //Cast to the source type
                setIL.Emit(OpCodes.Ldarg_2); //Load the second argument 
       //(value object)
                if (paramType.IsValueType)
       {
        setIL.Emit(OpCodes.Unbox, paramType); //Unbox it  
        if (typeOpCodes.ContainsKey(paramType)) //and load
        {
         var load = typeOpCodes[paramType];
         setIL.Emit(load);
        }
        else
        {
         setIL.Emit(OpCodes.Ldobj, paramType);
        }
       }
       else
       {
        setIL.Emit(OpCodes.Castclass, paramType); //Cast class
       }
                setIL.EmitCall(OpCodes.Callvirt,targetSetMethod, null); //Set the property value
      }
      else
      {
       setIL.ThrowException(typeof(MissingMethodException));
      }
            setIL.Emit(OpCodes.Ret);
            // Load the type
      dynamicType.CreateType();
            return newAssembly;
     }

    }

implementation is aggregated from different sources and main is this CodeProject article.

Sergey Mirvoda
Thanks @@Sergey Miroda...onw more thing Is there any relation between dynamic method and Reflection
Pankaj
Yes it is. Reflection.Emit is a part of .net reflection.
Sergey Mirvoda
also dynamic method is the __only__ way if you want to at runtime construct code that can be garbage collected.
Sergey Mirvoda
Thanks @@Sergey Mirvoda...
Pankaj
It is not very complicated, you simply write code in c#, compile it into assembly and open with reflector, switch to IL view and you will see code that copypastable ))
Sergey Mirvoda