前言

在上一章中介绍了什么是反射:

https://www.cnblogs.com/aoximin/p/16440966.html

正文

上一节讲述反射的基本原理和为什么要用反射,还用反射的优缺点这些。

其二者的本质是一致的,都是先获取到type(元数据)然后在进行创建实例。

下面那个好理解看下上面那个吧。

其实还是调用了activator:

说另外一个故事,是先有对象,后执行构造方法。还是先执行构造方法后有对象呢?到底是编译行为还是运行行为呢?

其实先创建对象,然后再进行构造函数。

而一切初始化其实是在构造函数中。

比如:

public class Cat
{
private string a = "100";
public string b = "100"; public Cat()
{
a = "200";
b = "200";
}
}

那么其.ctor () 为:

计算机远比我们想象的要简单的多,就是开辟一块空间,然后往里面填充数据。 至于定义什么类型,那属于程序的自我管理。

有点扯远了,那么反射的实现也是一样的。

在CreateInstance中:

两者创建对象的原理基本是一致的,反射只是在上面增加了一层动态获取类型(其中包括校验和创建实例的代码生成)。

玩一个有趣的东西,既然我们说了,其实创建对象其实不一定要构造函数的。且我们上面知道了RuntimeTypeHandle 可以创建对象,那就直接搞事情。

static void Main(string[] args)
{
Type catType = typeof(Cat);
Type handleType = Type.GetType("System.RuntimeTypeHandle");
var obj = Activator.CreateInstance(handleType);
var bind = BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static;
var hiMethod = handleType.GetMethod("Allocate", bind);
var cat= hiMethod.Invoke(obj, new object[]{catType}); Console.ReadKey();
}

得到的结果为:

好吧,接着往下看:

internal class Program
{
static void Main(string[] args)
{
var type1 = typeof(Cat);
Cat cat = new Cat();
var type2 =cat.GetType(); Assembly assembly = Assembly.GetExecutingAssembly();
var type3 = assembly.GetType("ConsoleApp1.Cat"); var type4 = typeof(Cat); Console.WriteLine($"{type1.GetHashCode()} {type1.GetHashCode()} {type3.GetHashCode()} {type4.GetHashCode()}");
Console.ReadKey();
} static (string name, int age, uint height) GetStudentInfo1()
{
return ("Bob", 28, 175);
}
}

他们的type也是同一个type:

internal class Program
{
static void Main(string[] args)
{
var type1 = typeof(Cat);
Cat cat = new Cat();
var type2 =cat.GetType(); Assembly assembly = Assembly.GetExecutingAssembly();
var type3 = assembly.GetType("ConsoleApp1.Cat"); var type4 = typeof(Cat); Console.WriteLine($"{type1.GetHashCode()} {type2.GetHashCode()} {type3.GetHashCode()} {type4.GetHashCode()}");
Console.ReadKey();
} static (string name, int age, uint height) GetStudentInfo1()
{
return ("Bob", 28, 175);
}
}

值得注意的是typeof 属于语法糖:

现在知道了Type 就包含我们类的元数据了,那么这些元数据到底有哪些呢?

里面包含了描述类的全部信息,有命名空间啊,属性啊,方法啊。这些都是有的。

这些不用去记,用的时候找找看,都有的。

唯一说一个值得的注意的地方哈。

是这样的。有一个BindingFlags这个枚举,可以看到是是一个多选枚举。

然后这样写:

static void Main(string[] args)
{
var type1 = typeof(Cat);
var filter = BindingFlags.Public;
var members = type1.GetMembers(filter); Console.ReadKey();
}

你发现看不到,这是为什么呢?

static void Main(string[] args)
{
var type1 = typeof(Cat);
var members = type1.GetMembers(); Console.ReadKey();
}

来看下是什么样的。

可以看到,这个public string b,其实是public | instance 这样的bindingflag,而不是public。

也就是说默认的是公共且可实例化的。 这个bindingflag的处理,不是或的关系,而是且的关系。

这里也是大家使用多选枚举值得注意的地方,我们的业务上不仅可以用来做或也可以用来做且,它是多选的意思。

如果需要看下反射方法是怎么调用的,可以去查看:System.RuntimeMethodHandle的InvokeMethod,这里面水比较深,选择性观看。

知道这个有什么用呢? 因为在执行invoke的时候会经过很多判断,如果是为了增加性能,可以直接调用System.RuntimeMethodHandle的InvokeMethod,一般不需要,只是说下优化手段。

例子

反射的常用手段,主要是一些例子。

获取某个namespace 下面的type:

static void Main(string[] args)

{

Assembly assembly = Assembly.GetExecutingAssembly();

var types = assembly.GetTypes().Where(u => u.Namespace == "ConsoleApp1");

Console.ReadKey();

}

这个比较常用,一般来说会先加载出types,得到一个集合,然后进行管理。

有一个初学者容易犯的错误,就是认为:

认为这种是属性,其实这个英文是property,是特性的意思,这在有些中文书上直接说成属性,这是错误的。

然后:

这种是attribute。

上面这种是字段,叫做field。

然后全部的这些,叫做member,都是成员:

这些概念是要区分开的。

第三个小栗子,如果获取静态的值:

static void Main(string[] args)
{
Type type = typeof(Cat);
var binding = BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static;
var a= type.GetProperties(binding); Cat.Test = "123456";
foreach (var item in a)
{
var test= item.GetValue(null);
Console.WriteLine($"test:{test}");
} Console.ReadKey();
}

上面要说明的是GetValue,对于静态可以填空。

我们讲述到前面的构造函数,都是默认的构造函数。

static void Main(string[] args)
{
Type type = typeof(Cat);
var cat = Activator.CreateInstance(type); Console.ReadKey();
}

这在一般情况下,很难适应,一般我们的构造函数在写一些复杂一点的时候,都会传入参数的。

public Cat(string a, string b)
{
this.a = a;
this.b = b;
}

这样的。那么怎么实例化呢?

static void Main(string[] args)
{
Type type = typeof(Cat);
var constructorInfo = type.GetConstructor(new Type[]{ typeof(string), typeof(string) });
var cat =constructorInfo.Invoke(new object[] { "123", "456"}); Console.ReadKey();
}

其他的方法也是这样。

上一节讲述了反射,这一节讲了一下反射的大致的行为和一些简单的例子。下一节可能是io流相关的,以前写过Java的,其实两者都一样,考虑是否重新整合一下。或者直接开篇异步篇。

重学c#系列—— 反射深入一点点[三十三]的更多相关文章

  1. 重学c#系列——字典(十一)

    前言 重学c#系列继续更新,简单看一下字典的源码. 看源码主要是解释一下江湖中的两个传言: 字典foreach 顺序是字典添加的顺序 字典删除元素后,字典顺序将会改变 正文 那么就从实例化开始看起,这 ...

  2. 重学c#系列——对c#粗浅的认识(一)

    前言 什么是c#呢? 首先你是如何读c#的呢?c sharp?或者c 井? 官方读法是:see sharp. 有没有发现开发多年,然后感觉名字不对. tip:为个人重新整理,如学习还是看官网,c# 文 ...

  3. 重学Golang系列(一): 深入理解 interface和reflect

    前言 interface(即接口),是Go语言中一个重要的概念和知识点,而功能强大的reflect正是基于interface.本文即是对Go语言中的interface和reflect基础概念和用法的一 ...

  4. 重学c#系列——c# 托管和非托管资源(三)

    前言 c# 托管和非托管比较重要,因为这涉及到资源的释放. 现在只要在计算机上运行的,无论玩出什么花来,整个什么概念,逃不过输入数据修改数据输出数据(计算机本质),这里面有个数据的输入,那么我们的内存 ...

  5. 重学c#系列——c# 托管和非托管资源与代码相关(四)

    前言 这是续第三节. 概况垃圾回收与我们写代码的关系: 强引用和弱引用 针对共享 Web 承载优化 垃圾回收和性能 应用程序域资源监视 正文 强引用和弱引用 垃圾回收器不能回收仍在引用的对象的内存-- ...

  6. 重学c#系列——异常(六)

    前言 用户觉得异常是不好的,认为出现异常是写的人的问题. 这是不全面,错误的出现并不总是编写程序的人的原因,有时会因为应用程序的最终用户引发的动作或运行代码的环境而发生错误,比如你用android4去 ...

  7. 重学c#系列——异常续[异常注意事项](七)

    前言 对上节异常的补充,也可以说是异常使用的注意事项. 正文 减少try catch的使用 前面提及到,如果一个方法没有实现该方法的效果,那么就应该抛出异常. 如果有约定那么可以按照约定,如果约定有歧 ...

  8. 重学c#系列——list(十二)

    前言 简单介绍一下list. 正文 这里以list为介绍. private static readonly T[] s_emptyArray = new T[0]; public List() { t ...

  9. 重学c#系列——datetime 和 datetimeoffset[二十一]

    前言 简单介绍一下datetime和 datetimeoffset. 正文 了解一个国家的文化,就要了解一个国家的历史. 要了解datetimeoffset,那么很有必要了解一下datetime. 表 ...

  10. 重学数据结构系列之——平衡树之SB Tree(Size Blanced Tree)

    学习来源:计蒜客 平衡树 1.定义 对于每一个结点.左右两个子树的高度差的绝对值不超过1,或者叫深度差不超过1 为什么会出现这样一种树呢? 假如我们依照1-n的顺序插入到二叉排序树中,那么二叉排序树就 ...

随机推荐

  1. 我操作MySQL的惊险一幕

    背景 前几天因工作需要,组长给我安排了一个数据清洗的任务. 任务:把 A 表的数据洗到 B 表. 我的第一反应,什么是「洗」?洗数据是什么?洗钱我倒是知道. 不过我不能慌啊,于是问了问组长. 我:组长 ...

  2. POJ2955 Brackets (区间DP)

    很好的区间DP题. 需要注意第一种情况不管是否匹配,都要枚举k来更新答案,比如: "()()()":dp[0][5]=dp[1][4]+2=4,枚举k,k=1时,dp[0][1]+ ...

  3. virtualbox的Linux虚拟磁盘大小调整及注意事项

    virtualBox 调整磁盘分区 起因 起初安装centos6.3 时,没有修改默认的硬盘空间.只有8G,导致后面安装完zookeeper,jdk之后,在安装mysql发现磁盘空间不足 扩容步骤 1 ...

  4. 【pytest官方文档】解读- 插件开发之hooks 函数(钩子)

    上一节讲到如何安装和使用第三方插件,用法很简单.接下来解读下如何自己开发pytest插件. 但是,由于一个插件包含一个或多个钩子函数开发而来,所以在具体开发插件之前还需要先学习hooks函数. 一.什 ...

  5. Shading-JDBC、ShadingSphere、ShardingProxy 使用详解

    ShadingSphere ​ShardingSphere是一款起源于当当网内部的应用框架,2015年在当当网内部诞生,2016年由主要开发人员张亮带入京东数科,在国内经历了当当网.电信翼支付.京东数 ...

  6. react 可视化编辑器1

    可视化编辑器1 前言 前面我们学习低代码,例如百度的低代码平台 amis,也有相应的可视化编辑器,通过拖拽的方式生成配置文件.就像这样 笔者自己也有类似需求:比如中台有个归档需求,通过选择一些配置让后 ...

  7. NLP之基于BERT的预测掩码标记和句间关系判断

    BERT @ 目录 BERT 程序步骤 程序步骤 设置基本变量值,数据预处理 构建输入样本 在样本集中随机选取a和b两个句子 把ab两个句子合并为1个模型输入句,在句首加入分类符CLS,在ab中间和句 ...

  8. QML 怎么调用 C++ 中的内容?

    以下内容为本人的学习笔记,如需要转载,请声明原文链接微信公众号「englyf」https://mp.weixin.qq.com/s/z_JlmNe6cYldNf11Oad_JQ 先说明一下测试环境 编 ...

  9. costool - 腾讯云cos快捷工具。

    目录 使用截图 使用方法 配置文件 安装方法 其他 一个腾讯云cos(对象存储)非官方快速上传和下载的工具,使用官方go-sdk二次开发.可以用于以下场景. 备份一些配置文件,比如.bashrc .v ...

  10. 畅联新设备接入情况:新增威隆NB烟感

    双美接入,应该是电信AEP平台的. ---------------------------------------------------------------------------------- ...