Type对象
要使用反射,首先要获取Type对象。Type对象包含C#对象的各种信息,例如名称,命名空间的名称等等。使用typeof
运算符,可以从一个类名获取Type对象。
Type type = typeof(int);
还可以在Object对象上调用GetType方法来获取一个Type对象。
Type type = i.GetType();
获得Type对象之后,就可以调用上面的方法和属性,来查看有关类型的信息了。注意Type对象查看的类的信息,而不是具体绑定到某个对象的信息。
Console.WriteLine($"基类是:{type.BaseType}");
Console.WriteLine($"类型全名是:{type.FullName}");
Console.WriteLine($"所在的程序集是:{type.Assembly}");
Console.WriteLine($"该类型是否是接口:{type.IsInterface}");
ParameterInfo对象
通过ParameterInfo对象可以得到参数的信息。详细情况可以查看MSDN库。
MemberInfo对象
通过MemberInfo对象可以查看有关类中成员的信息。其中有大量的方法和属性,详情可以参阅MSDN。
MemberInfo的ToString()方法返回成员信息的字符串。所以我们可以这样简单的获取一个类的所有成员信息。
MemberInfo[] members = type.GetMembers();
foreach (MemberInfo member in members)
{
Console.WriteLine($"{member}");
}
MethodInfo对象
利用MethodInfo对象,我们可以知道关于方法的大量信息,详情请参阅MSDN库。
在这里,我们利用MethodInfo和ParameterInfo对象,可以组合得到方法签名的信息。其实也可以简单的在遍历的时候使用MethodInfo对象的ToString()方法,但是这个方法只会返回方法参数列表的类型名,不会返回参数名。
MethodInfo[] methods = type.GetMethods();
foreach (MethodInfo method in methods)
{
//创建新的字符串构造类,组合方法的信息
StringBuilder sb = new StringBuilder();
//组合方法返回值的类型
sb.AppendFormat($"{method.ReturnParameter.ParameterType} ");
//组合方法名称
sb.AppendFormat($"{method.Name}(");
//获得参数列表信息
ParameterInfo[] parameters = method.GetParameters();
foreach (ParameterInfo parameter in parameters)
{
//组合参数列表信息
sb.AppendFormat($"{parameter}, ");
}
//删除参数最后的多余的逗号
if (parameters.Length >= 1)
{
sb.Remove(sb.Length - 2, 2);
}
sb.Append(")");
//组合完毕,显示字符串
Console.WriteLine(sb.ToString());
读取并使用对象
上面的方法都是静态的读取某一个类的信息。其实利用反射还可以做更多事情,例如动态读取一个对象并执行其中的方法。
首先先来随意构造一个类。
class Otaku
{
private string name;
public Otaku()
{
name = "DefaultName";
}
public string Name
{
get
{
return name;
}
set
{
name = value;
}
}
public string[] LovedCartoons()
{
return new string[] { "One Piece", "RWBY", "Sword Art Online" };
}
}
然后就可以利用上面的步骤来动态获取并调用该对象的方法了。
MyConsole.PrintNextSection("动态获取对象");
Type type = typeof(Otaku);
Otaku otaku =(Otaku)type.GetConstructor(Type.EmptyTypes).Invoke(null);
PropertyInfo property = type.GetProperty("Name");
//原来的属性值
Console.WriteLine($"原值:{otaku.Name}");
property.SetValue(otaku, "new otaku");
//新的属性值
Console.WriteLine($"新值:{otaku.Name}");
//获取MethodInfo并动态调用
MethodInfo method = type.GetMethod("LovedCartoons");
string[] returnValues = (string[])method.Invoke(otaku, null);
foreach (string value in returnValues)
{
Console.Write(value + ", ");
}
Console.WriteLine();
反射的作用
通过反射我们可以动态获取对象并调用方法。初看之下貌似没有什么作用,因为利用反射可以做到的事情不用反射照样也可以做到。其实,反射的最重要的作用就在于这动态 二字。
如果不利用反射,想要编写代码组合类的话,就必须硬编码到代码里面,这在某些情况下就不适用了。比如在编写Web程序的过程中,有很多工作都是相同的,如果每次都硬编码的话,不仅效率不高,而且很多情况下也容易犯错。这时候利用反射特性,将不变的工作固定下来,变动的工作分离出来,可以大大提高工作效率。不过真正的作用还是需要自己在实际工作中去体会。