【Unity|C#】基础篇(12)——反射(Reflection)(核心类:Type、Assembly)

【学习资料】

  《C#图解教程》(第24章):https://www.cnblogs.com/moonache/p/7687551.html
  电子书下载:https://pan.baidu.com/s/1mhOmBG0

【内容】

  对以下文章的整合:

  知识点:

    • 用途
    • 命名空间
    • 主要类: System.Type  System.Reflection.Assembly 
    • System.Type类
      • 说明
      • 获取给定类型的Type的3种方式
      • Type类的 常用属性
      • Type类的 常用方法
    • 用反射生成对象
      • ConstructorInfo
      • Activator.CreateInstance
    • 使用Type反射举例(创建对象、获取并设置字段或属性、调用方法)
    • Assembly类
      • 用途
      • Assembly常用方法
      • 使用举例
    • 扩展知识
      • Assembly三种加载方式(Load、LoadFrom、LoadFile)的区别


【文章整合笔记】

    • .NET的应用程序由几个部分:程序集(Assembly)、模块(Module)、类型(class)组成
    • 反射是.NET中的重要机制,通过反射,可以 在运行时,获得程序或程序集中 每一个类型(包括类、结构、委托、接口和枚举等)的 成员和成员的信息
    • 有了反射,即可对每一个类型了如指掌。另外我还可以直接创建对象,即使这个对象的类型在编译时还不知道。

        

  • 用途

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

    •  System.Reflection 
    •  System.Type 
    •  System.Reflection.Assembly 
  • 用到的主要类

    •  System.Type 类                // 通过这个类可以访问任何给定数据类型的信息。 
    •  System.Reflection.Assembly 类 // 它可以用于访问给定程序集的信息,或者把这个程序集加载到程序中。 
  • System.Type类
    • System.Type 类对于反射起着核心的作用
    • 但它是一个抽象的基类,Type有与每种数据类型对应的派生类,我们使用这个派生类的对象的方法、字段、属性来查找有关该类型的所有信息
    • 程序中用到的每一个类型,CLR都会创建一个包含这个类型信息的Type类型的对象
    • 程序中用到的每一个类型,都会关联到独立的Type类型的对象
    • 不管创建的类型有多少个实例,只有一个Type对象会关联到所有这些实例

        

    • 获取给定类型Type引用的 3种方式:

      • typeof()
      • Type t = typeof(string);
      • object.GetType()
      • string s = "hello";
        Type t = s.GetType(); 
      • Type.GetType() :类型的完整名称(包含命名空间名)
      • Type t = Type.GetType("System.String"); 
    • Type类的常用属性  (以string为例)

        

    • Type类的常用方法

      • 注:只能获取  public  的成员(字段、属性、方法、事件、构造函数)

        

  • 通过反射生成对象

    • 用 ConstructorInfo 生成对象

      • System.Type t = typeof(string);
        // 获取参数为char[]的构造函数: string(char[])
        System.Reflection.ConstructorInfo ci = t.GetConstructor(new Type[] { typeof(char[]) });
        // 等价于 object obj = new string( new char[] { ‘h‘, ‘e‘, ‘l‘, ‘l‘, ‘o‘ } )
        object obj = ci.Invoke(new object[] { new char[] { ‘h‘, ‘e‘, ‘l‘, ‘l‘, ‘o‘ } });  
    • 用 Activator 生成对象
      • System.Type t = typeof(string);
        // 等价于 object obj = new string( new char[] { ‘h‘, ‘e‘, ‘l‘, ‘l‘, ‘o‘ } )
        object obj2 = Activator.CreateInstance(t, new char[] { ‘h‘, ‘e‘, ‘l‘, ‘l‘, ‘o‘ });
  • 使用Type反射举例(创建对象、获取并设置字段或属性、调用方法)

    • public class MyTest
      {
          // 字段
          public int value1  = 1;
          private int value2 = 2;
          // 属性
          public string name1    { get; set; } = "hello";
          protected string name2 { get; set; } = "world";
          // 方法
          public void Show1()   { Debug.Log(name1 + value1); }
          internal void Show2() { Debug.Log(name2 + value2); }
      }
      
      void Start()
      {
          // 获取 MyTest类 的 Type类型
          Type t = typeof(MyTest);
      
          // 使用Activator创建对象
          object obj = Activator.CreateInstance(t);
      
          // 获取字段
          FieldInfo obj_value1 = t.GetField("value1");
          FieldInfo obj_value2 = t.GetField("value2");        // null,无法获取 private 字段
          // 获取属性
          PropertyInfo obj_name1 = t.GetProperty("name1");
          PropertyInfo obj_name2 = t.GetProperty("name2");    // null,无法获取 protected 字段
          // 获取方法
          MethodInfo obj_Show1 = t.GetMethod("Show1");
          MethodInfo obj_Show2 = t.GetMethod("Show2");        // null,无法获取 internal 字段
      
          // 设置字段 SetValue
          obj_value1.SetValue(obj, 10);
          // 设置属性 SetValue
          obj_name1.SetValue(obj, "heihei");
          // 调用方法 Invoke
          obj_Show1.Invoke(obj, null);
      }
    • 运行结果

        

  • Assembly类
    • 用途

      • 使用Assembly类可以降低程序集之间的耦合,有利于软件结构的合理化
      • 获得程序集的信息
      • 动态的加载程序集
      • 在程序集中查找类型信息
      • 创建该类型的实例
    • 常用的方法

        

    • 使用举例

      • namespace MyNameSpace
        {
            public class LearnCS : MonoBehaviour
            {
                public class MyTest
                {
                    public class MySubTest { }
                }
        
                void Start()
                {
                    // 加载程序集,获取Assembly实例
                    Assembly ass1 = Assembly.Load("Assembly-CSharp");
                    Assembly ass2 = Assembly.LoadFrom("C:/E/Projects/Demo/Library/ScriptAssemblies/Assembly-CSharp.dll");
                    Assembly ass3 = Assembly.LoadFile("C:/E/Projects/Demo/Library/ScriptAssemblies/Assembly-CSharp.dll");
        
                    // 获取MyTest类型所在的程序集Assembly
                    Assembly ass = Assembly.GetAssembly(typeof(MyTest));
                    // 获取当前运行的程序集Assembly
                    Assembly assembly = Assembly.GetExecutingAssembly();
        
                    // 获取程序集名称信息
                    string assembly_FullName = assembly.FullName;
                    AssemblyName assembly_Name = assembly.GetName();
                    // 获取程序集路径
                    string assembly_CodeBase = assembly.CodeBase;
                    string assembly_Location = assembly.Location;
        
                    // 获取Type
                    Type[] types = assembly.GetTypes();
                    Type t = assembly.GetType("MyNameSpace.LearnCS+MyTest");         // 通过Type的FullName
        
                    // 创建实例
                    var obj = assembly.CreateInstance("MyNameSpace.LearnCS+MyTest"); // 通过Type的FullName
                }
            }
        }
    • 运行结果

        



【扩展知识】

    • Load

      • 使用 程序集名 加载,Load("xxx")
      • 同时会 加载依赖 的其他程序集
      • 效率最高,优先使用这个方式
    • LoadFrom
      • 使用 路径 加载,LoadFrom("x/xx/xxx.dll")
      • 可以通过URL加载("http://www.abc.com/test.dll"),会被下载到缓存文件中
      • 同时会 加载依赖 的其他程序集
      • 加载过的程序集,不会重新加载
      • 不能用于加载标识相同但路径不同的程序集
    • LoadFile
      • 使用 路径 加载,LoadFile("x/xx/xxx.dll")
      • 不会加载依赖 的程序集
      • 可以多次加载同一个程序集
      • 可以用来加载和检查具有相同标识但位于不同路径中的程序集,但不会加载程序的依赖项

原文地址:https://www.cnblogs.com/shahdza/p/12261831.html

时间: 2024-11-05 15:53:35

【Unity|C#】基础篇(12)——反射(Reflection)(核心类:Type、Assembly)的相关文章

cocos2dx基础篇(12)——点九图CCScale9Sprite

[引言] 本来是想学学控件类CCControl的另一个子类按钮控件CCControlButton的.但是发现里面有一个参数牵扯到CCScale9Sprite这个类.看到CCScale9Sprite,很容易联想到精灵类CCSprite.两者又有什么区别呢?因此我就去网上收了一些有关CCScale9Sprite的资料来学习. [参考文献] [1] http://blog.csdn.net/nynyvkhhiiii/article/details/12782249 [2] http://www.cnb

Java 基础篇之反射

Java 基础篇之反射 反射# 使用反射获取程序运行时的对象和类的真实信息. 获取 Class 对象# 每个类被加载之后,系统会为该类生成一个对应的 Class 对象,通过该 Class 对象可以访问到 JVM 中的这个类. 使用 Class 类的 forName(String clazzName) 静态方法.字符串参数的值是某个类的全限定类名,必须包含完整的包名 调用某个类的 class 属性 调用某个对象的 getClass() 方法.该方法是 java.lang.Object 类中的一个方

2000条你应知的WPF小姿势 基础篇<63-68 Triggers和WPF类逻辑结构>

原文:2000条你应知的WPF小姿势 基础篇<63-68 Triggers和WPF类逻辑结构> 在正文开始之前需要介绍一个人:Sean Sexton. 来自明尼苏达双城的软件工程师.最为出色的是他维护了两个博客:2,000ThingsYou Should Know About C# 和 2,000 Things You Should Know About WPF .他以类似微博式的150字简短语言来每天更新一条WPF和C#重要又容易被遗忘的知识.很希望能够分享给大家. 本系列我不仅会翻译他的每

Unity&amp;Shader基础篇-绘制网格+圆盘

一.前言 尊重原创,转载请注明出处凯尔八阿哥专栏 上一章点击打开链接中已经画出了一个棋盘网格,首先来完善一下这个画网格的Shader,添加属性,属性包括网格的线的宽度,网格的颜色等.代码如下: Shader "Unlit/Chapter2-2" { Properties { _backgroundColor("面板背景色",Color) = (1.0,1.0,1.0,1.0) _axesColor("坐标轴的颜色",Color) = (0.0,0

linux基础篇-12,grep正则表达式与扩展正则表达式

################################################ 基本正则表达式:grep 使用正则表达式定义的模式来过滤文本 grep -i :不区分大小写 --color -v:显示没被匹配的任意行 -o:只显示被匹配的字符串 -E 扩展的正是表达式 =egerp -A#:#为数字 -B#: -C#: [[email protected] testcp]# grep -o 'root' /etc/passwd --color root root root ro

python 基础篇 12 装饰器进阶

本节主要内容:1. 通?装饰器回顾2. 函数的有?信息3. 带参数的装饰器4. 多个装饰器同时装饰?个函数 ?. 通?装饰器的回顾开闭原则: 对增加功能开放. 对修改代码封闭装饰器的作?: 在不改变原有代码的基础上给?个函数增加功能通?装饰器的写法: 执行过程: 其实执行  target_func()就是执行inner函数.  inner函数会先执行目标函数之前的代码,然后执行目标函数,之后再执行目标函数之后的代码. 如何获取函数的有用信息: 函数名.__name__可以查看函数名字 函数名._

【Unity|C#】基础篇(6)——正则表达式(Regex类)

[学习资料] > 在线文档 官方文档:https://docs.microsoft.com/zh-cn/dotnet/csharp/ 菜鸟教程:https://www.runoob.com/csharp/csharp-tutorial.html > 视频教程 腾讯学院.Siki学院         > 书籍 <C#图解教程>:https://www.cnblogs.com/moonache/p/7687551.html [笔记] 匹配规则传送门:https://www.run

(spring-第17回【AOP基础篇】) 创建增强类

一.   增强类包含的信息: a)   横切逻辑(插入的具体代码) b)   部分连接点信息(在方法的哪个位置插入代码,比如方法前.方法后等). 二.   增强的类型 每一种增强有一个需要实现的增强类. a)   前置增强 顾名思义,在目标方法前实施增强. 增强类:org.springframework.aop.MethodBeforeAdvice. 举例,三步走: 1)   第一步,创建目标类接口和目标类: 2)   第二步,实现MethodBeforeAdvice,创建增强类: 3)   第

java基础篇---反射机制

一.JAVA是动态语言吗? 一般而言,说到动态言,都是指在程序运行时允许改变程序结构或者变量类型,从这个观点看,JAVA和C++一样,都不是动态语言. 但JAVA它却有着一个非常突出的动态相关机制:反射.通过反射,Java可以于运行时加载.探知和使用编译期间完全求和的类.生成其对象实体,调用其方法或者对属性设值.所以Java算是一个半动态的语言吧. 反射的概念: 在Java中的反射机制是指在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法; 对于任意一个对象,都能够调用它的任意一个方