程序集

程序集是代码进行编译是的一个逻辑单元,把相关的代码和类型进行组合,然后生成PE文件。程序集只是逻辑上的划分,一个程序集可以只由一个文件组成,也可由多个文件组成。不管是单文件程序集还是多文件程序集,它们都由固定的结构组成

常见的两种程序集:

  可执行文件(.exe文件)和 类库文件(.dll文件)。

在VS开发环境中,一个解决方案可以包含多个项目,而每个项目就是一个程序集。

应用程序结构:

  包含 应用程序域(AppDomain),程序集(Assembly),模块(Module),类型(Type),成员(EventInfo、FieldInfo、MethodInfo、PropertyInfo) 几个层次

他们之间是一种从属关系,也就是说,一个AppDomain能够包括N个Assembly,一个Assembly能够包括N个Module,一个Module能够包括N个Type,一个Type能够包括N个成员。他们都在System.Reflection命名空间下。【公共语言运行库CLR】加载器 管理 应用程序域,这种管理包括  将每个程序集加载到相应的应用程序域  以及  控制每个程序集中类型层次结构的内存布局

从【应用程序结构】中不难看出程序集Assembly的组成:

MemberInfo 该类是一个基类,它定义了EventInfo、FieldInfo、MethodInfo、PropertyInfo的多个公用行为 

一个程序运行起来以后,有一个应用程序域(AppDomain),在这个应用程序域(AppDomain)中放了我们用到的所有程序集(Assembly)。我们所写的所有代码都会编译到【程序集】文件(.exe .dll)中,并在运行时以【Assembly对象】方式加载到内存中运行,每个类(Class  Interface)以【Type对象】方式加载到内存,类的成员(方法,字段,属性,事件,构造器)加载到内存也有相应的对象。

详细:https://www.cnblogs.com/luna-hehe/p/10143748.html

程序集的结构:

程序集元数据,类型元数据,MSIL代码,资源。

程序集元数据,程序集元数据也叫清单,它记录了程序集的许多重要信息,是程序集进行自我说明的核心文档。当程序运行时,CLR 通过这份清单就能获取运行程序集所必需的全部信息。清单中主要主要包含如下信息:标识信息(包括程序集的名称、版本、文化和公钥等);文件列表(程序集由哪些文件组成);引用程序集列表(该程序集所引用的其他程序集);一组许可请求(运行这个程序集需要的许可)。

类型元数据,类型元数据列举了程序集中包含的类型信息,详细说明了程序集中定义了哪些类,每个类包含哪些属性和方法,每个方法有哪些参数和返回值类型,等等。

MSIL代码,程序集元数据和类型元数据只是一些辅助性的说明信息,它们都是为描述MSIL代码而存在的。MSIL 代码是程序集的真正核心部分,正是它们实现了程序集的功能。比如在“Animals”项目中,五个动物类的C#代码最终都被转换为MSIL 代码,保存在程序集Animals.dll 中,当运行程序时,就是通过这些MSIL 代码绘制动物图像的。

资源,程序集中还可能包含图像、图标、声音等资源。

私有程序集和共享程序集

私有程序集是仅供单个软件使用的程序集,安装很简单,只需把私有程序集复制到软件包所在文件夹中即可。而那些被不同软件共同使用的程序就是共享程序集,.NET类库的程序集就是共享程序集,共享程序集为不同的程序所共用,所以它的部署就不像私有程序集那么简单,必须考虑命名冲突和版本冲突等问题。解决这些问题的办法是把共享程序集放在系统的一个特定文件夹内,这个特定文件夹称为全局程序集高速缓存(GAC)。这个过程可用专门的.NET 工具完成

程序集的特性

// 将 ComVisible 设置为 false 使此程序集中的类型对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型,则将该类型上的 ComVisible 属性设置为 true。
[assembly: ComVisible(false)]

// 如果此项目向 COM 公开,则下列 GUID 是用于类型库的 ID
[assembly: Guid("816a1507-8ca5-438d-87b4-9f3bef5b2481")]

// 程序集的版本信息由下面四个值组成:主版本、次版本、内部版本号、修订号
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

程序集的属性信息是由特性实现的,与普通特性的不同的是,描述程序集的特性前要添加前缀“assembly:”

原文链接:https://www.cnblogs.com/Sweepingmonk/p/10867975.html

Assembly 程序集对象

Assembly 是一个抽象类,我们用的都是RuntimeAssembly的对象。

获得程序集的方式:

  • 获得当前程序域中的所有程序集
    • Assembly[] ass = AppDomain.CurrentDomain.GetAssemblies();
    • 所有用到过得aessembly。如果只是add ref了,没有在程序中用到,AppDomain.CurrentDomain.GetAssemblies()中没有。用到时才被JIT加载到内存。
    • 每个app都有一个AppDomain,OS不允许其他app访问这个程序的AppDomain
  • 获得当前对象所属的类所在的程序集
    • this.GetType().Assembly;
    • Type对象肯定在一个assembly对象中
    • 可以通过Type对象得到程序集
  • 根据路径加载程序集

    • Assembly.LoadFrom(assPath);
Assembly assembly = Assembly.LoadFrom(@"E:\Work\VSCode\ConsoleApp1\ClassLibrary1\bin\Debug\netstandard2.0\ClassLibrary1.dll");
Type[] allTypes = assembly.GetTypes();
Type stu = assembly.GetType("ClassLibrary1.Student");
object stu1 = Activator.CreateInstance(stu);
Console.WriteLine(stu1);

Type 类型对象

Type 是一个抽象类,我们用的都是TypeInfo类的对象。

程序运行时,一个class对应一个Type类的对象。通过Type对象可以获得类的所有信息。

获得Type对象的方式:

  • 通过类获得对应的Type
    • Type t1 = typeof(Person);
  • 通过对象获得Type用assembly对象,通过类的full name类获得type对象
    • Type t2 = person.GetType();  
    • this.GetType();
    • Type stu = assembly.GetType("ClassLibrary1.Student");
  • 获得程序集中定义的所有的public类

    • Type[] allPublicTypes = ass1.GetExportedTypes();
  • 获得程序集中定义的所有的类

    • Type[] allTypes = ass1.GetTypes();

Type类的属性:

  • t.Assembly; 获取t所在的程序集

  • t.FullName; 获取t所对应的类的full name

  • t.Name; 获取t所对应的类的 name

  • t.IsArray; 判断t是否是一个数组类

  • t.IsEnum; 判断t是否是一个枚举类

  • t.IsAbstract; 判断t是否是一个抽象类

  • t.IsInterface; 判断t是否是一个interface

Type类的方法:

  • notebookInterfaceType.IsAssignableFrom(Type t);判断t是否实现了 notebookInterfaceType 接口

  • t.IsSubclassOf(Type parent); t是否是parent的子类

  • t.IsInstanceOfType(object o); o是否是t类的对象

  • t.GetFields();  //method, property  得到所有的public的fields,methods,properties

  • t.GetField("gender"); 根据名字得到某个field

Type类示例:

static void TypeTest1()
        {
            Person p = new Person { Name = "NaNa", Age = 5 };
            Type typePerson = p.GetType();

            //搜索具有指定名称的公共属性
            PropertyInfo pf = typePerson.GetProperty("Name");
            pf.SetValue(p, "LiLi", null);
            Console.WriteLine(p.Name);

            //返回所有公共属性
            PropertyInfo[] props = typePerson.GetProperties();
            StringBuilder builder = new StringBuilder(30);
            foreach (PropertyInfo item in props)
            {
                builder.Append(item.Name + "=" + item.GetValue(p, null) + "\n");
            }
            builder.Append("----------------------\n");

            //返回所有公共字段
            FieldInfo[] fieIds = typePerson.GetFields();
            foreach (FieldInfo item in fieIds)
            {
                builder.Append(item.Name + "=" + item.GetValue(p) + "\n");
            }
            builder.Append("----------------------\n");

            //返回所有公共方法
            MethodInfo[] methods = typePerson.GetMethods();
            foreach (MethodInfo item in methods)
            {
                builder.Append(item + "\n");
            }
            builder.Append("----------------------\n");
            Console.WriteLine(builder);

            //返回所有公共构造函数
            ConstructorInfo[] cons = typePerson.GetConstructors();
            foreach (ConstructorInfo item in cons)
            {
                //Name都是 .ctor  
                Console.WriteLine(item.Name + "\n");
                //构造函数的参数个数  
                Console.WriteLine(item.GetParameters().Length + "\n");

                ParameterInfo[] parames = item.GetParameters();
                foreach (var pars in parames)
                {
                    Console.WriteLine(pars.Name+""+pars.ParameterType);
                }
            }
        }
View Code

原文链接:https://blog.csdn.net/CJB_King/article/details/80521481

反射概念:

1. 在程序运行时动态获取类或对象的信息,具体包括了

动态 获取 加载程序集(Assmebly)

动态 获取 类型信息(如类、接口 等) - Type对象

动态 获取 类型的成员信息(如方法,字段,属性等);

2. 在运行时,动态创建类型实例(new),以及 调用 和 访问 这些 实例 成员;

.Net反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为.Net的反射机制。

.Net反射机制主要提供了以下功能: 在运行时判断任意一个对象所属的类;在运行时构造任意一个类的对象;在运行时判断任意一个类所具有的成员变量和方法;在运行时调用任意一个对象的方法;

类型作用
Assembly定义和加载程序集,加载在程序集清单中列出的模块,以及从此程序集中查找类型并创建该类型的实例。
Module包含模块的程序集以及模块中的类等。还可以获取在模块上定义的所有全局方法或其他特定的非全局方法。
ConstructorInfo构造函数的名称、参数、访问修饰符(如 public 或 private)和实现详细信息(如 abstract 或 virtual)等。使用Type的 GetConstructors 或 GetConstructor 方法来调用特定的构造函数。
MethodInfo
方法的名称、返回类型、参数、访问修饰符(如 public 或 private)和实现详细信 息(如 abstract 或 virtual)等。使用Type的 GetMethods 或 GetMethod 方法来调用特定的方法。
FieldInfo字段的名称、访问修饰符(如 public 或 private)和实现详细信息(如 static)等;并获取或设置字段值。
EventInfo事件的名称、事件处理程序数据类型、自定义属性、声明类型和反射类型等;并添加或移除事件处理程序。
PropertyInfo属性的名称、数据类型、声明类型、反射类型和只读或可写状态等;并获取或设置属性值。
ParameterInfo参数的名称、数据类型、参数是输入参数还是输出参数,以及参数在方法签名中的位置等

在程序运行时,动态获取程序集:

class Program
    {
        static void Main(string[] args)
        {
            Assembly[] ass = AppDomain.CurrentDomain.GetAssemblies();
            Person p = new Person();
            p.TestAssembly();

            Console.ReadKey();
        }
    }


class Person
    {
        public string Name { get; set; }
        public int Age { get; set; }
        private int Id;
        public double Sum;

        public void Method1() { }
        private void Method2() { }

        public void TestAssembly()
        {
            Assembly ass = this.GetType().Assembly;
            Console.WriteLine(ass);
            Type[] types = ass.GetTypes();
            foreach (var item in types)
            {
                Console.WriteLine(item + "   (types)");
            }
            Type currentType = ass.GetType();
            Console.WriteLine(currentType);
            Type typeByFullName = ass.GetType("ConsoleApp2.Person");
            Console.WriteLine(typeByFullName);

            Type type = this.GetType();
            Console.WriteLine(type);
            MethodInfo[] methods = this.GetType().GetMethods();
            foreach (var item in methods)
            {
                Console.WriteLine(item + "    (methods)");
            }
            var members = this.GetType().GetMembers();
            foreach (var item in members)
            {
                Console.WriteLine(item);
            }
            var member = this.GetType().GetMember("Name");
            foreach (var item in member)
            {
                Console.WriteLine(item);
            }
            FieldInfo field = type.GetField("Sum");
            Console.WriteLine(field);
            PropertyInfo prop = type.GetProperty("Name");
            Console.WriteLine(prop);
        }
    }
View Code

在程序运行时,动态创建 类型实例:在Person类中加下面4个方法,在Main中测试

class Program
    {
        static void Main(string[] args)
        {
            Person p = new Person();
            p.CreatePersonObject();

            Console.ReadKey();
        }
    }



public void CreatePersonObject()
        {
            Type type = this.GetType();
            Person p = Activator.CreateInstance(type) as Person;
            Person p1 = Activator.CreateInstance<Person>();

            PropertyInfo prop = type.GetProperty("Name");
            prop.SetValue(p1, "toto",null);
            Console.WriteLine(p1.Name);

            MethodInfo method = type.GetMethod("SayHi");
            method.Invoke(p1, null);
            MethodInfo method1 = type.GetMethod("ShowNumber");
            object[] arrParams = { 13 };
            method1.Invoke(p1, arrParams);
            MethodInfo method2 = type.GetMethod("GetString");
            string retStr = method2.Invoke(p1, null).ToString();
            Console.WriteLine(retStr);
        }

        public void SayHi()
        {
            Console.WriteLine("Hiiiiiiiiiiii");
        }
        public void ShowNumber(int no)
        {
            Console.WriteLine(no);
        }
        public string GetString()
        {
            return "Hello";
        }
View Code

通过反射找出类型的构造函数,然后调用构造函数来获取实例引用

public static void GetConstructor()
        {
            Type tpdatetime = Type.GetType("System.DateTime", false);
            if (tpdatetime != null)
            {
                ConstructorInfo constructor = tpdatetime.GetConstructor(new Type[] { typeof(int), typeof(int), typeof(int), typeof(int), typeof(int), typeof(int) });
                if (constructor != null)
                {
                    object instance = constructor.Invoke(new object[] { 2019, 12, 17, 16, 11, 24 });
                    if (instance != null)
                    {
                        PropertyInfo[] props = tpdatetime.GetProperties(BindingFlags.Public | BindingFlags.Instance);
                        Console.WriteLine("以下是DateTime实例的属性值列表");
                        foreach (PropertyInfo item in props)
                        {
                            object objval = item.GetValue(instance,null);
                            Console.WriteLine("{0,-15}:{1}",item.Name,objval??string.Empty);
                        }
                    }
                }
            }
        }
View Code

原文链接:https://www.cnblogs.com/czx1/p/201413137070-com.html

通过反射调用类的私有成员:

Person p = new Person();
Type tPerson = p.GetType();
//得到私有字段的值:
FieldInfo privateField = tPerson.GetField("privateFields", BindingFlags.Instance | BindingFlags.NonPublic);
//设置私有成员的值:
privateField.SetValue(p, "修改后的私有字段值");
Console.WriteLine(privateField.GetValue(p));

//得到私有属性的值: 
PropertyInfo privateProp = tPerson.GetProperty("PrivateProperties", BindingFlags.Instance | BindingFlags.NonPublic);
//设置私有属性的值:
privateProp.SetValue(p, "修改后的私有属性值",null);
Console.WriteLine(privateProp.GetValue(p,null));

//调用私有方法
MethodInfo privateMethod = tPerson.GetMethod("SayHi", BindingFlags.Instance | BindingFlags.NonPublic);
privateMethod.Invoke(p, null); 

 

 

12-22 17:18