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有啥用,感觉节约空间有限.

原文地址:https://www.cnblogs.com/frogkiller/p/12312611.html

时间: 2024-10-17 21:03:00

clr via c# 程序集加载和反射(2)的相关文章

clr via c# 程序集加载和反射集(一)

1,程序集加载---弱的程序集可以加载强签名的程序集,但是不可相反.否则引用会报错!(但是,反射是没问题的) //获取当前类的Assembly Assembly.GetEntryAssembly() //通过Load方法加载程序集 Assembly.Load //通过LoadFrom加载指定路径名的程序集--可以时url对象. Assembly LoadFrom(string path) //只是反射,并确保程序集中的数据不被执行. ReflectionOnlyLoadFrom() Reflec

第23章 程序集加载和反射

程序集加载和反射,实现了在编译时对一个类型一无所知的情况下,如何在运行时发现类型的信息,创建类型的实例以及访问类型的成员.显现的功能以及效果是十分强大的,比如使用第三方提供的程序集,以及创建动态可扩展应用程序. 23.1 程序集加载 JIT编译器在将方法的IL代码编译成本地代码时,会查看IL代码中引用了哪些类型.在运行时,JIT编译器查看元数据表TypeRef和AssemblyRef来确定哪一个程序集定义了所引用的类型.在AssemblyRef元数据表的记录项中,包含了构成程序集强名称的各个部分

CLR中的程序集加载

本次来讨论一下基于.net平台的CLR中的程序集加载的机制: [注:由于.net已经开源,可利用vs2015查看c#源码的具体实现] 在运行时,JIT编译器利用程序集的TypeRef和AssemblyRef元数据表来确定哪一个程序集定义了所引用的类型.在AssemblyRef元数据表的记录项中,包含构成程序集的强名称的各个部分.JIT编译器获取包括名称(无扩展名和路径).版本.语言文化和公钥标记,将这些连接成一个字符串.JIT编译器将该标识匹配的一个程序集加载到AppDomain中.] CLR内

程序集加载与反射(二):实例篇

目录: 上篇:程序集加载与反射(一):基础篇 Demo:下载 一.Demo 下面这个Demo,使用了策略模式模仿了一下插件机制.我们举个一邮件发送的例子: 1.一个策略类库:Strategy,里面定义了邮件需要实现的接口:IEmailStrategy. using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespa

程序集加载与反射

目录 程序集加载 获取类型信息 构造类型实例 通过反射发现成员 调用成员 一.程序集加载 Load方法:CLR通过调用System.Rreflection.Assemblly类的静态方法来显示加载程序集. public static Assembly Load(AssemblyName assemblyRef); public static Assembly Load(string assemblyString); LoadFrom方法:同样我们可以使用 远程加载程序集.此方法首先打开程序集,并

第二十三章 程序集加载和反射

目录: 23.1 程序集加载 23.2 使用反射构建动态可扩展应用程序 23.3 反射的性能 23.4 设计支持加载项的应用程序 23.5 使用反射发现类型的成员 23.1 程序集加载 JIT编译器将方法的IL代码编译成本机代码时,会查看IL代码中引用了哪些类型.在运行时,JIT编译器利用程序集的TypeRef和AssemblyRef元数据表来确定哪一个程序集定义了所有引用的类型. 通过Assembly的Load方法加载程序集. 23.2 使用反射构建动态可扩展应用程序 23.3 反射的性能 2

程序集加载和反射

一.程序集加载 1,根据程序集名称查找程序集 public class Assembly { public static Assembly Load(AssemblyName assemblyRef); public static Assembly Load(string assemblyString); //未列出不常用的Load重载 } Assembly.Load("ConsoleApplication2");, 2,根据程序集文件路径名(包含扩展名)查找程序集 public cl

程序集加载与反射(二):实战篇

目录: 上篇:http://www.cnblogs.com/sunchong/p/4550476.html Demo 一.Demo 下面这个Demo,使用了策略模式模仿了一下插件机制.我们举个一邮件发送的例子: 1.一个策略类库:Strategy,里面定义了邮件需要实现的接口:IEmailStrategy. using System; using System.Collections.Generic; using System.Linq; using System.Text; using Sys

第一节:程序集加载

我们知道JIT编译器将方法的IL代码编译成本地代码时,会查看IL代码中引用了哪些类型.在运行时,JIT编译器利用程序集的TypeRef和AssemblyRef元数据表来确定哪一个程序集定义了所引用的类型.在AssemblyRef元数据表的记录项中,包含了构成程序集强名称的各个部分.JIT编译器获取所有这些部分,包括名称(无扩展名和路径).版本.语言文化和公钥标记,并把它连接成一个字符串.然后,JIT编译器尝试将与该标识匹配的一个程序集加载到AppDomain中(如果还没有加载的话).如果被加载的