2009-12-25 154 views
14

我想學習使用c#的動態方法及其實例。
動態方法和Reflection之間是否有任何關係?
請幫幫我。動態方法的實例?

+0

我不明白朮語_dynamic method_。 Delphi有動態方法,對此C#沒有類比,並且有一種編程技術叫做_dynamic programming_。或者你的意思是_virtual method_? 我假設,「Reflation」是指反射。 – 2009-12-25 07:36:29

+3

沒有人在那裏也有一個動態方法的概念# – Pankaj 2009-12-25 07:38:30

回答

5

您可以通過DynamicMethod類創建一個方法。

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 on MSDN
我要指出,使用這種方法的發展是非常緩慢的,而不是非常有用的。

+0

@VMAtm ..我讀過DynamicMethod的一些文章,在某處我發現它們比Reflection.DynamicMethod更快,它們消除了編寫自定義序列化和反序列化代碼的需要。 – Pankaj 2009-12-25 07:58:24

+1

我的意思是開發速度 - 維護這樣的代碼不是非常快速和非常困難。 – VMAtm 2009-12-25 08:06:10

+0

ILGenerator - 是System.Reflection.Emit的一部分 在某種程度上它是反射和動態方法之間的關係 – VMAtm 2009-12-25 10:01:29

8

我們使用動態方法來加速反射。 這是我們的反射優化器的代碼。它比直接調用和2000倍的速度是反射調用

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; 
     } 

    } 

實現從不同來源聚集,主要是這CodeProject上的文章僅慢10%。

+0

謝謝@@ Sergey Miroda ... onw more thing動態方法和反射之間有任何關係 – Pankaj 2009-12-25 09:40:37

+0

是的。 Reflection.Emit是.net反射的一部分。 – 2009-12-25 17:25:50

+2

如果您想在運行時構建可以被垃圾收集的代碼,動態方法也是__only__方法。 – 2009-12-25 17:49:43

相關問題