摘自: http://dingxiaowei.cn/2019/06/21/

# 前言

我们都知道反射在编程语言里是非常方便也是非常强大的,但或许有人觉得在学习或者工作中用的可能并不是那么多,我的理解是反射在写框架和写工具时用的比较多。举个栗子:写一个 Excel 的表格编辑器,我们能够在控制台修改 Excel 里的内容,或许有人觉得这有啥难的,直接手撸 Model, 如果哪天策划手滑或者手贱修改了命名,或者增加 / 减少一列,那我们程序是不是也要跟着修改,因为我们保存数据或许是写死的字段名,如果全部通过反射,那就随便策划怎么折腾 excel, 我有反射神器,我也不怕!至于为啥要写 Excel 的编辑器,或许有人会疑惑,我直接在 Excel 里修改不行嘛,这样策划要修改个数据然后要导出数据,然后在游戏里跑,会比较麻烦,如果有对应的表格编辑器直接在游戏运行时就修改测试就很方便,如果是 bool 类型就给策划 toggle 选项,如果是枚举类型就弄下拉框,如果是范围类型就给个 Range, 这样策划就不会填错,如果编辑器是基于反射做的,不是字段写死的,策划随便修改 excel 字段都不会出问题.

# 反射获取属性

1
typeof(Animal).GetProperties();

# 反射获取 / 设置属性的值

获取值

1
properities[i].GetValue(a);

获取的值是 object 类型的,如果想要转换成真实类型,然后调用对应类型的扩展方法可以通过 if 去一个一个判断然后强转,还没想到特别方便的转换方式,也有看到过 Convert.ChangeType, 但返回值类型还是 Object, 不是我想要的.

设置值

1
properties[i].SetValue(a,object xxx)

# 反射调用字段的扩展方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;

namespace ConsoleApp1
{
public class Animal
{
public int ID { get; set; }
public string Name { get; set; }
}

public static class Extension
{
public static string GetStringValue(this int v)
{
return "我是Int类型:" + v;
}

public static string GetStringValue(this string v)
{
return "我是String类型:" + v;
}
}
class Program
{
static void Main(string[] args)
{
Animal a = new Animal() { ID = 1, Name = "mimi" };

var properities = typeof(Animal).GetProperties();
var thisassembly = typeof(Animal).Assembly;
for (int i = 0; i < properities.Length; i++)
{
var v = properities[i].GetValue(a);
foreach (var m in GetExtensionMethods(thisassembly, v.GetType()))
{
var vv = m.Invoke(null, new object[] { v });
Console.WriteLine(vv);
}
}

Console.Read();
}


//反射获取扩展方法
static IEnumerable<MethodInfo> GetExtensionMethods(Assembly assembly,
Type extendedType)
{
var query = from type in assembly.GetTypes()
where type.IsSealed && !type.IsGenericType && !type.IsNested
from method in type.GetMethods(BindingFlags.Static
BindingFlags.Public BindingFlags.NonPublic)
where method.IsDefined(typeof(ExtensionAttribute), false)
where method.GetParameters()[0].ParameterType == extendedType
select method;
return query;
}

}
}

我在一开始没用上述反射获取扩展方法时,直接用的 xxx.GetType ().GetMethod (“GetStringValue”) 是获取不到这个扩展方法的, 至于为啥普通方式获取不到扩展方法,这个要看 IL 层的设计了,事实上一个类的扩展方法并不属于该类,而是属于定义他的静态类,之所以能够调用,是因为编译器做了手脚的缘故,编译器遇到这种状况就会调用静态类的方法,通过其 IL 就可以看到真实的调用情况。

# 更多反射 API

还是参考官方文档最丰富呀。 https://docs.microsoft.com/zh-cn/dotnet/api/system.reflection.propertyinfo?view=netframework-4.8# 属性 参考链接 https://codeday.me/bug/20170729/42358.html 更多文章 http://dingxiaowei.cn/

更新于

请我喝[茶]~( ̄▽ ̄)~*

Solvarg 微信支付

微信支付

Solvarg 支付宝

支付宝

Solvarg 贝宝

贝宝