基本反射使用

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
    [MenuItem("Tools/测试反射")]
public static void TestReflection()
{
TestForReflection test = new TestForReflection();
test.isTest = true;
test.Id = 1;
test.Name = "test";

object nameValue = null;
Type testType = test.GetType();

MemberInfo[] members = testType.GetMember("Name", BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static);//必须要添加BindingFlags.Instance | BindingFlags.Static,BindingFlags都使用位运算

while (members == null || members.Length == 0)//如果当前Type没有,就从BaseType开始找
{
testType = testType.BaseType;
if (testType == null)
{
return;
}
members = testType.GetMember("Name",BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static);
}
switch (members[0].MemberType)
{
case MemberTypes.Field:
nameValue = testType.GetField("Name", BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static).GetValue(test);
break;
case MemberTypes.Property:
nameValue = testType.GetProperty("Name",BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static).GetValue (test);
break;
default:
break;
}
Debug.Log(nameValue);
}
public class TestForReflection
{
public int Id;
public string Name;
public bool isTest;
}

反射得到属性和变量的方法封装

将上述反射方法封装一下,再进行调用

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
[MenuItem("Tools/测试反射")]
public static void TestReflection()
{
TestForReflection test = new TestForReflection();
test.isTest = true;
test.Id = 1;
test.Name = "test";

object nameValue = null;
nameValue = GetMemberValue(test, "Name");
Debug.Log(nameValue);
}
/// <summary>
/// 反射类里面属性和变量的值
/// </summary>
/// <param name="obj">想要反射的类</param>
/// <param name="memberName">想要反射的属性或变量的名字</param>
/// <param name="bindingAttr">bindingFlags</param>
/// <returns>属性和变量的值</returns>
private static object GetMemberValue(object obj,string memberName, BindingFlags bindingAttr = BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static)
{
Type testType = obj.GetType();

MemberInfo[] members = testType.GetMember(memberName, bindingAttr);//必须要添加BindingFlags.Instance | BindingFlags.Static,BindingFlags都使用位运算

while (members == null || members.Length == 0)//如果当前Type没有,就从BaseType开始找
{
testType = testType.BaseType;
if (testType == null)
{
return null;
}
members = testType.GetMember(memberName, bindingAttr);
}
switch (members[0].MemberType)
{
case MemberTypes.Field:
return testType.GetField(memberName, bindingAttr).GetValue(obj);
case MemberTypes.Property:
return testType.GetProperty(memberName, bindingAttr).GetValue(obj);
default:
return null;
}
}

反射list

我们给TestForReflection添加一个List<string>

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
    [MenuItem("Tools/测试反射")]
public static void TestReflection()
{
TestForReflection test = new TestForReflection();
test.isTest = true;
test.Id = 1;
test.Name = "test";
test.testList = new List<string>() { "1", "2", "3" };

object list = GetMemberValue(test,"testList");
int listCount = System.Convert.ToInt32(list.GetType().InvokeMember("get_Count", BindingFlags.Default | BindingFlags.InvokeMethod, null, list, new object[] { }));
for (int i = 0; i < listCount; i++)
{
object item = list.GetType().InvokeMember("get_Item",BindingFlags.Default | BindingFlags.InvokeMethod,null,list, new object[] { i });
Debug.Log(item);
}

//Debug.Log(listCount);
}

public class TestForReflection
{
public int Id;
public string Name;
public bool isTest;
public List<string> testList;
}

我们先用list.GetType()得到list的Type,也就是System.Collections.Generic.List1[System.String]`

然后使用InvokeMember方法,反射调用List类的"get_Count"方法,当我们使用InvokeMember方法时,它的参数有:

public object? InvokeMember (string name, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder? binder, object? target, object?[]? args);

第一个参数就是"get_Count",第二个参数是BindingFlags.Default | BindingFlags.InvokeMethod,这个也算是固定用法,BindingFlags.InvokeMethod就是配合InvokeMember方法的。第三个参数Binder我们设为null,第四个参数target我们需要传一个有实例的object,因为"get_Count"并不是一个静态方法,如果我们要调用就必须传一个target。第五个参数我们传一个空的数组,一般这个参数数组就是用来传"get_Count"所需要的参数的。

反射自定义class的list

上面的例子我们反射的是List<string>,在实际使用中,我们大多数情况下会反射自定义类。

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
    [MenuItem("Tools/测试反射")]
public static void TestReflection()
{
TestForReflection test = new TestForReflection();
test.isTest = true;
test.Id = 1;
test.Name = "test";
test.testList = new List<string>() { "1", "2", "3" };
test.testList2 = new List<TestForListReflection>
{
new TestForListReflection{ Id = 1, Name = "test1" },
new TestForListReflection{ Id = 2, Name = "test2" },
new TestForListReflection{ Id = 3, Name = "test3" },
};

//object list = GetMemberValue(test,"testList");
//int listCount = System.Convert.ToInt32(list.GetType().InvokeMember("get_Count", BindingFlags.Default | BindingFlags.InvokeMethod, null, list, new object[] { }));
//for (int i = 0; i < listCount; i++)
//{
// object item = list.GetType().InvokeMember("get_Item",BindingFlags.Default | BindingFlags.InvokeMethod,null,list, new object[] { i });
// Debug.Log(item);
//}

object list2 = GetMemberValue(test, "testList2");
int list2Count = System.Convert.ToInt32(list2.GetType().InvokeMember("get_Count", BindingFlags.Default | BindingFlags.InvokeMethod, null, list2, new object[] { }));
for (int i = 0; i < list2Count; i++)
{
object item = list2.GetType().InvokeMember("get_Item", BindingFlags.Default | BindingFlags.InvokeMethod, null, list2, new object[] { i });
object id = GetMemberValue(item, "Id");
object name = GetMemberValue(item, "Name");
Debug.Log(id + " " + name);
}
//Debug.Log(listCount);
}
public class TestForReflection
{
public int Id;
public string Name;
public bool isTest;
public List<string> testList;
public List<TestForListReflection> testList2;
}
public class TestForListReflection
{
public int Id { get; set; }
public string Name { get; set; }
}

通过反射创建实例

封装Activator.CreateInstance

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/// <summary>
/// 将类的实例通过反射创建
/// </summary>
/// <param name="name">类名</param>
/// <returns>类的实例</returns>
private static object CreateClassInstance(string name)
{
object obj = null;
Type type = null;
foreach (Assembly asm in AppDomain.CurrentDomain.GetAssemblies())
{
Type curType = asm.GetType(name);
if (curType != null)
{
type = curType;
break;
}
}
if(type != null)
{
obj = Activator.CreateInstance(type);
}
return obj;
}

通过反射创建实例并赋值

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
    [MenuItem("Tools/测试反射创建")]
public static void TestReflection2()
{
object obj = CreateClassInstance("TestForReflection");

PropertyInfo idInfo = obj.GetType().GetProperty("Id");
idInfo.SetValue(obj, Convert.ToInt32("11"));
PropertyInfo nameInfo = obj.GetType().GetProperty("Name");
nameInfo.SetValue(obj,"ATAO");
PropertyInfo boolInfo = obj.GetType().GetProperty("isTest");
boolInfo.SetValue(obj, Convert.ToBoolean("true"));
PropertyInfo floatInfo = obj.GetType().GetProperty("Height");
floatInfo.SetValue(obj, Convert.ToSingle("12.5"));
PropertyInfo enumInfo = obj.GetType().GetProperty("TestEn");
object enumValue = TypeDescriptor.GetConverter(enumInfo.PropertyType).ConvertFromInvariantString("Test1");
enumInfo.SetValue(obj, enumValue);

TestForReflection test = obj as TestForReflection;
Debug.Log(test.Id + " " + test.Name + " " + test.isTest + " " + test.Height + " " + test.TestEn);
}


public class TestForReflection
{
public int Id { get; set; }
public string Name { get; set; }
public bool isTest { get; set; }
public float Height { get; set; }
public TestEnum TestEn { get; set; }
//public List<string> testList;
// public List<TestForListReflection> testList2;
}
public enum TestEnum
{
None = 0,
Test1 = 1,
Test2 = 2,
}

注意Enum的转换方式:使用TypeDescriptor.GetConverter得到Enum的转换器,然后调用ConvertFromInvariantString

只有这样我们才能调用PropertyInfo.SetValue来设置枚举的值

封装SetValue方法

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
[MenuItem("Tools/测试反射创建")]
public static void TestReflection2()
{
object obj = CreateClassInstance("TestForReflection");

PropertyInfo idInfo = obj.GetType().GetProperty("Id");
SetValue(idInfo, obj, "11", "int");
PropertyInfo nameInfo = obj.GetType().GetProperty("Name");
SetValue(nameInfo, obj, "ATAO", "string");
PropertyInfo boolInfo = obj.GetType().GetProperty("isTest");
SetValue(boolInfo, obj, "true", "bool");
PropertyInfo floatInfo = obj.GetType().GetProperty("Height");
SetValue(floatInfo, obj, "12.3", "float");
PropertyInfo enumInfo = obj.GetType().GetProperty("TestEn");
SetValue(enumInfo, obj, "Test2", "enum");

TestForReflection test = obj as TestForReflection;
Debug.Log(test.Id + " " + test.Name + " " + test.isTest + " " + test.Height + " " + test.TestEn);
}
/// <summary>
/// 将反射的属性进行赋值
/// </summary>
/// <param name="info">反射的属性</param>
/// <param name="var">此属性所在的obj</param>
/// <param name="value">赋值</param>
/// <param name="type">类型</param>
private static void SetValue(PropertyInfo info, object var, string value,string type)
{
object val = (object)value;

switch (type)
{
case "int":
val = Convert.ToInt32(val);
break;
case "float":
val = Convert.ToSingle(val);
break;
case "bool":
val = Convert.ToBoolean(val);
break;
case "enum":
val = TypeDescriptor.GetConverter(info.PropertyType).ConvertFromInvariantString(val.ToString());
break;
}
info.SetValue(var, val);
}

通过反射创建List

通过反射创建普通List

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
    [MenuItem("Tools/测试反射创建")]
public static void TestReflection2()
{
object obj = CreateClassInstance("TestForReflection");

//...
Type stringType = typeof(string);
Type listType = typeof(List<>);
Type listGenericType = listType.MakeGenericType(new System.Type[] { stringType });
object listObj = Activator.CreateInstance(listGenericType,new object[] {});//需要参数

for (int i = 0; i < 3; i++)
{
string itemStr = "TestList" + i;
listObj.GetType().InvokeMember("Add",BindingFlags.Default | BindingFlags.InvokeMethod,null,listObj,new object[] {itemStr});
}

obj.GetType().GetField("testList").SetValue(obj, listObj);

TestForReflection test = obj as TestForReflection;
//...
test.testList.ForEach(x => { Debug.Log(x); });
}


public class TestForReflection
{
public int Id { get; set; }
public string Name { get; set; }
public bool isTest { get; set; }
public float Height { get; set; }
public TestEnum TestEn { get; set; }
public List<string> testList { get; set; }
public List<TestForListReflection> testList2 { get;set; }
}

注意看创建时使用的API

封装创建泛型ListType的方法

1
2
3
4
5
6
7
8
9
10
/// <summary>
/// 创建泛型ListType
/// </summary>
/// <param name="type">泛型类型</param>
/// <returns></returns>
private static object CreateListGenericType(Type type)
{
Type listGenericType = typeof(List<>).MakeGenericType(new System.Type[] {type});
return Activator.CreateInstance(listGenericType,new object[] {});
}

通过反射创建自定义类List

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
[MenuItem("Tools/测试反射创建")]
public static void TestReflection2()
{
object obj = CreateClassInstance("TestForReflection");

//...


object testListObj = CreateListGenericType(typeof(TestForListReflection));
for (int i = 0; i < 3; i++)
{
object testIns = CreateClassInstance("TestForListReflection");
PropertyInfo testIdInfo = testIns.GetType().GetProperty("Id");
SetValue(testIdInfo, testIns, i.ToString(), "int");
PropertyInfo testNameInfo = testIns.GetType().GetProperty("Name");
SetValue(testNameInfo, testIns, i.ToString() + "Test","string");
testListObj.GetType().InvokeMember("Add",BindingFlags.Default | BindingFlags.InvokeMethod,null,testListObj,new object[] {testIns});
}

obj.GetType().GetProperty("testList2").SetValue (obj, testListObj);

TestForReflection test = obj as TestForReflection;
//...
test.testList2.ForEach(x => { Debug.Log(x.Id + " " + x.Name); });
}