前言

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

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

正文

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

重学c#系列—— 反射的基本理解[三十三]-小白菜博客

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

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

重学c#系列—— 反射的基本理解[三十三]-小白菜博客

其实还是调用了activator:

重学c#系列—— 反射的基本理解[三十三]-小白菜博客

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

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

重学c#系列—— 反射的基本理解[三十三]-小白菜博客

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

比如:

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

那么其.ctor () 为:

重学c#系列—— 反射的基本理解[三十三]-小白菜博客

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

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

在CreateInstance中:

重学c#系列—— 反射的基本理解[三十三]-小白菜博客

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

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);
	}
}
重学c#系列—— 反射的基本理解[三十三]-小白菜博客

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

重学c#系列—— 反射的基本理解[三十三]-小白菜博客

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

重学c#系列—— 反射的基本理解[三十三]-小白菜博客

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

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

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

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

重学c#系列—— 反射的基本理解[三十三]-小白菜博客

然后这样写:

static void Main(string[] args)
{
	var type1 = typeof(Cat);
	var filter = BindingFlags.Public;
	var members = type1.GetMembers(filter);
	
	Console.ReadKey();
}
重学c#系列—— 反射的基本理解[三十三]-小白菜博客

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

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

来看下是什么样的。
重学c#系列—— 反射的基本理解[三十三]-小白菜博客

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

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

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

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

上一节结束了反射,这一节讲了一下反射的大致的行为。下一节反射的常用手段,主要是一些例子。