2009-12-25 37 views
14

Tôi muốn tìm hiểu phương pháp động và ví dụ thực tế của nó bằng cách sử dụng C#.
Có mối quan hệ nào giữa phương pháp động và Phản xạ không?
Xin hãy giúp tôi.Ví dụ thực tế về phương pháp động?

+0

Tôi không hiểu thuật ngữ _dynamic method_. Delphi có các phương thức động, trong đó C# không có sự tương tự, và có một kỹ thuật lập trình được gọi là _dynamic programming_. Hay bạn có nghĩa là _virtual method_? Tôi giả sử, bằng cách "Từ chối", bạn có nghĩa là phản chiếu. –

+3

không có người đàn ông cũng có một khái niệm về phương pháp năng động trong C# – Pankaj

Trả lời

5

Bạn có thể tạo phương thức qua lớp 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
tôi nên lưu ý rằng sự phát triển sử dụng phương pháp này là rất chậm và không phải là rất hữu ích.

+0

@VMAtm .. tôi đã đọc một số bài viết của DynamicMethod, một nơi nào đó tôi thấy rằng họ là nhanh hơn sau đó reflection.DynamicMethod họ cũng loại bỏ sự cần thiết phải viết serialization & deserialization mã tùy chỉnh. – Pankaj

+1

Tôi có nghĩa là tốc độ phát triển - nó không phải là rất nhanh và rất khó để duy trì mã như vậy. – VMAtm

+0

ILGenerator - là một phần của System.Reflection.Emit Trong phần nào nó là một mối quan hệ giữa Reflection và phương pháp năng động – VMAtm

8

Chúng tôi đang sử dụng các phương pháp động để tăng tốc độ phản ánh. Đây là mã của trình tối ưu hóa phản chiếu của chúng tôi. nó chỉ chậm hơn 10% so với cuộc gọi trực tiếp và nhanh hơn 2000 lần so với cuộc gọi phản chiếu

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

    } 

thực hiện được tổng hợp từ các nguồn khác nhau và chính là bài viết CodeProject này.

+0

Cảm ơn @@ Sergey Miroda ... onw nhiều điều Có mối quan hệ nào giữa phương pháp động và Reflection – Pankaj

+0

Có đúng vậy. Reflection.Emit là một phần của sự phản chiếu .net. –

+2

cũng là phương pháp động là cách __only__ nếu bạn muốn chạy thi công mã có thể được thu thập rác. –

Các vấn đề liên quan