zoukankan      html  css  js  c++  java
  • clr via c# 程序集加载和反射(2)

    查看,clr via c# 程序集加载和反射(1)


    8,发现类型的成员:

    字段,构造器,方法,属性,事件,嵌套类型都可以作为类型成员.其包含在抽象类MemberInfo中,封装了所有类型都有的一组属性.

    MemeberInfo的派生列表:

    System.Reflection.MemberInfo
        System.Reflection.EventInFo

        System.Reflection.FieldInfo
        System.Reflection.MethodBase
               System.Reflection.ConstructorInfo

               System.Reflection.MethodInfo
        System.Reflection.PropertyInfo
       System.Reflection.TypeInfo

    •    显示Type的特性---在特性中已经有描述不再讲述
    •    显示Type的MemberInfo

      

    public static void DisplayType(Type t)
            {
    
               // Display(0, "Assembly:{0}", t.Assembly.FullName);
                //Display(0, "FullName:{0}", t.FullName);
                //DisplayAttribute(1, assembly);
                Display(0, "");
                Display(0, "Type:{0}'s Members:", t.Name);
                //DisplayAttribute(1, t);
                foreach (MemberInfo mi in t.GetTypeInfo().DeclaredMembers)
                {
                    string typeName = string.Empty;
                    if (mi is Type) typeName = "Nested Type";
                    if (mi is FieldInfo) typeName = "FieldInfo";
                    if (mi is MethodInfo) typeName = "MethodInfo";
                    if (mi is ConstructorInfo) typeName = "ConstructInfo";
                    if (mi is PropertyInfo) typeName = "PropertyInfo";
                    if (mi is EventInfo) typeName = "EventInfo";
                    Display(0,"");
                   // DisplayAttribute(1, mi);
                    Display(1, "{0}: {1}", mi.GetType().Name, mi);
    
                }
    
    
            }

        MemberInfo的几个重要属性

                  Name:返回成员的名称

                  DeclaringType:返回声明了成员的Type的类型.比如mi的Declaring Type 是 t;

                  Module:返回声明了成员的模块:比如,上述mi的模块是ClrFromCSharp_2_2.exe,表示其在这个文件中.

                  CustomAttributes ,返回一个IEnumerable<CustomAttributeData> ,表示该成员的定制特性的一个实列的属性.

       除了使用DeclaredMembers

                还可以使用

                             GetDeclaredNestedType:返回嵌套类别

                             GetDeclaredField:返回字段

                             GetDeclaredMethod:返回方法

                             GetDeclaredProperty:返回属性

                             GetDeclaredEvent:返回事件

                             GetConstructor:返回特定的构造器

                             GetConstructors:返回所有构造器

        对于构造器,方法,属性访问器方法(get,set),事件方法(add,remove)

      •               可以调用GetParameterInfo获取ParameterInfo构成的数组,从而了解成员的参数的类型.还可以
      •               查询只读属性ReturnParameter获得一个ParameterInfo的返回类型对象,表示成员的返回类型.
      •               对于泛型对象,可以调用GetGenericArguments来获取他们的类型参数的集合

    9,调用类型的成员.

          使用InvokeMember方法调用成员的列子已经在前面讲过了.

          1,使用绑定到成员并且调用:

     internal sealed class SomeType//调试所有到的类
            {
                public Int32 m_someField;
                public SomeType(ref Int32 x) { x *= 2; }//设定构造器使用Ref形参,需要Type.GetType("System.Int32&")or typeof(int).MakeRefType();
                public override string ToString()
                {
                    // throw new Exception("tostring err");
                    return m_someField.ToString();
                }
                public Int32 SomeProp
                {
                    get
                    {
                        return m_someField;
                    }
                    set
                    {
    
                        if (value < 1) throw new ArgumentOutOfRangeException();//模拟内部错误,注意,只有Release模式可以捕获,不然会出错.
    
                        m_someField = value;
    
                    }
                }
                public event EventHandler SomeEvent;
                private void NoCompilerWarnings()
                {
                    SomeEvent.ToString();
                }
                public int this[int index]//模拟索引器.
                {
                    get
                    {
                        return m_someField + index;
                    }
                    set
                    {
                        m_someField = value + index;
                    }
                }
    
            }

           2,通过Member调用

    public static void BindToMemberThenInvokeTheMember(Type t)
            {
    
                Display(0, MethodInfo.GetCurrentMethod().Name);
                //构造实列
                object[] args = new object[] { 1 };
                ConstructorInfo ctor = t.GetConstructor(new Type[] { typeof(int).MakeByRefType() });
                Display(0, "Called before .ctor,args0 is {0}", args[0].ToString());
                object obj=ctor.Invoke(args);
                Display(0, "Called after .ctor,args0 is {0}", args[0].ToString());
    
                //读写字段
                FieldInfo fi = t.GetTypeInfo().GetField("m_someField");
                fi.SetValue(obj, 33);
                Display(0, "m_someField={0}", fi.GetValue(obj));
    
                //调用方法
                MethodInfo mi = t.GetTypeInfo().GetDeclaredMethod("ToString");
                string s = mi.Invoke(obj, null) as string;
                Display(0, "tostring is " + s);
    
                //读写属性
                PropertyInfo pi = t.GetTypeInfo().GetProperty("SomeProp");
                try
                {
    
                    t.InvokeMember("SomeProp", BindingFlags.SetProperty | BindingFlags.Public | BindingFlags.Instance, null, obj, new object[] { 0 });
                }
                catch(TargetInvocationException e)//注意反射出错的类型.以及原类型引用.
                {
                    if (e.InnerException.GetType() != typeof(ArgumentOutOfRangeException)) throw;
                    Console.WriteLine("catched the Reflection error ,but in ReleaseMode");
                }
    
                //读写索引器属性
                PropertyInfo pi1 = t.GetTypeInfo().GetDeclaredProperty("Item");
                pi1.SetValue(obj, 100, new object[] { 200 });
                Display(0, pi1.GetValue(obj, new object[] { 200 }).ToString());
                //为事件添加和删除委托
                EventInfo ei = t.GetTypeInfo().GetDeclaredEvent("SomeEvent");
                ei.AddEventHandler(obj, new EventHandler((sender, e) => Display(0, e.ToString())));
                ei.RemoveEventHandler(obj, new EventHandler((sender, e) => Display(0, e.ToString())));
    
            }        }

          3,通过CreateDelegate调用

    public static void BindToMemberInvokeByDelegate(Type t)
            {
                //构造对象
                object[] args = new object[] { 10 };
                object obj = Activator.CreateInstance(t,args);
                //调用方法
                MethodInfo mi = obj.GetType().GetTypeInfo().GetDeclaredMethod("ToString");
                dynamic toString = mi.CreateDelegate(typeof(Func<string>), obj);//利用动态类型简化操作.
                string str = toString();
                Display(0, str);
                //读写属性
                PropertyInfo pi = obj.GetType().GetTypeInfo().GetDeclaredProperty("SomeProp");
                dynamic setSomeProp =pi.SetMethod.CreateDelegate(typeof(Action<int>), obj);
                try
                {
                    setSomeProp(0);
                }
                catch (ArgumentOutOfRangeException)
                {
                    Console.WriteLine("Property set catch.");
                }
                setSomeProp(2);
                dynamic getSomeProp = pi.GetMethod.CreateDelegate(typeof(Func<int>), obj);
                Display(0, getSomeProp().ToString());
                //向事件增加删除委托
                EventInfo ei = t.GetTypeInfo().GetDeclaredEvent("SomeEvent");
                dynamic addEventHandler = ei.AddMethod.CreateDelegate(typeof(Action<EventHandler>), obj);
                var removeEventHandler = (Action<EventHandler>)ei.RemoveMethod.CreateDelegate(typeof(Action<EventHandler>), obj);
                addEventHandler(new EventHandler((x, y) => Display(0, y.ToString())));
                removeEventHandler(new EventHandler((x, y) => Display(0, y.ToString())));
            }

    1,使用dynamic简化类型转换.否则,需要类型转换后才能使用

    2,使用GetMethod,SetMethod,AddMethod,RemoveMethod,来调用属性和事件的方法.

    3,注意,异常变成了ArgumentOutOfRangeException

       4,使用Dynamic的方法简化

    public static void UseDynamicInvokeMember(Type t)
            {
                //构造对象
                object[] args = new object[] { 10 };
                dynamic obj = Activator.CreateInstance(t, args);
                //读写字段
    
                try
                {
                    obj.m_someField = 5;
                    int v = obj.m_someField;
                    Console.WriteLine("someField" + v);
                }
                catch(RuntimeBinderException e)
                {
                    Display(0,"faild to access field:" + e.Message);
                }
                //调用方法
                dynamic str = obj.ToString();
                Display(0, "Tostring" + str);
                //读写属性
                try
                {
                    obj.SomeProp = 0;
                }
                catch (ArgumentOutOfRangeException)
                {
                    Display(0, "Property set catch");
                }
                obj.SomeProp = 2;
                dynamic val = obj.SomeProp;
                Display(0, "SomeProp" + val);
                obj.SomeEvent += new EventHandler((x, y) => Display(0, y.ToString()));
                obj.SomeEvent -= new EventHandler((x, y) => Display(0, y.ToString()));
            }

      

    10,使用绑定句柄减少进程的内存消耗

        在System定义了三个句柄

      •     RuntimeTypeHandle
      •     RuntimeFieldHandle
      •     RuntimeMethodHandle
    • 将Type对象转换为一个RuntimeHandle对象,调用 Type.GetTypeHandle静态方法
    • 将RuntimeTypeHandle转换为Type对象,调用 GetTypeFromHandle
    • 要将FieldInfo转换为RuntimeFieldHandle,使用FieldInfo的实列只读属性FieldHandle
    • 要将RuntimeFieldHandle转换为FieldInfo,调用FieldInfo.GetFieldFromHandle.
    • 要将MethodInfo准换RuntimeMethodHandle,查新实列只读属性MethodHandle
    • 使用MEthodINfo.GetMethodInfoFromHandle,返回MethodInfo对象
     public static void CallHandleDifference()
            {
                BindingFlags c_bf = BindingFlags.FlattenHierarchy | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
                showHeap(0, "Before doing something");
                List<MethodBase> mis = new List<MethodBase>();
                foreach (Type t in typeof(object).Assembly.ExportedTypes)
                {
                    if (t.IsGenericTypeDefinition) continue;
                    MethodBase[] mb = t.GetMethods(c_bf);
                    mis.AddRange(mb);
                }
                Display(0, "# of methods={0:N0}", mis.Count);
                showHeap(0, "after building cache of MEthodInfo objects");
                List<RuntimeMethodHandle> mish = mis.ConvertAll<RuntimeMethodHandle>(x => x.MethodHandle);
                showHeap(0, "holding Methodinfo and runtimehandle");
                GC.KeepAlive(mis);
                mis = null;
                showHeap(0, "After free MethodInfo objects");
                mis = mish.ConvertAll<MethodBase>(x => MethodBase.GetMethodFromHandle(x));
                showHeap(0, "Re builds methodinfo objects");
                GC.KeepAlive(mis);
                GC.KeepAlive(mish);
                showHeap(0,"end the thread...");
            }
            private static void showHeap(int indent,string s)
            {
                Console.WriteLine("{0}Heap size={1,12:N0} - {2}", new string(' ', indent * 3), GC.GetTotalMemory(true), s);//该函数会回收内存.
            }

       GC.GetTotalMemory(true)会回收内存.

       不太明白这个Handle有啥用,感觉节约空间有限.

  • 相关阅读:
    mysql导出导入数据库和表学习笔记
    gitlab+jenkins学习笔记
    mysql数据库的备份与恢复
    第十二天python3 匿名函数
    第十三天python3 生成器yield
    [Todo]Java反序列化-weblogic
    bcrypt浅析
    AWD准备
    Linux下提权练习
    wordpress站点被恶意重定向
  • 原文地址:https://www.cnblogs.com/frogkiller/p/12312611.html
Copyright © 2011-2022 走看看