C#的反射System.Reflection正对于C#的整体代码结构:
命名空间Namespace一般与程序集Assembly名称一致。
一个程序集Assembly由多个类型Type【interface,class,struct,enum,delegate】组成。
一个类型Type由方法Method,字段Field,属性Property,事件Event等成员等组成。
一个属性Property可能含有特性Attribute。
一个方法Method有返回类型,方法名,参数列表,是否是静态等组成
方法的参数Parameter有类型,参数名,默认值,是否引用参数ref,是否输出参数out
一、新建.net core控制台应用程序ReflectionDemo,右键 解决方案-->添加---->新建项目
选择类库项目,输入类库名称TestClassLibrary。
右键控制台项目ReflectionDemo,添加 引用 ,勾选项目 TestClassLibrary,点击 确定。
二、删除类库TestClassLibrary的默认类Class1.cs。新建两个类Employee.cs和TestClass.cs
1).Employee.cs的源程序如下:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
namespace TestClassLibrary
{
/// <summary>
/// 员工信息类
/// </summary>
public class Employee
{
/// <summary>
/// 编号
/// </summary>
public int Id { get; set; }
/// <summary>
/// 姓名
/// </summary>
[DisplayName("员工姓名")]
public string Name { get; set; }
/// <summary>
/// 地址
/// </summary>
public string Address { get; set; }
/// <summary>
/// 入职日期
/// </summary>
public DateTime JoinDate { get; set; }
/// <summary>
/// 打印员工信息
/// </summary>
public void PrintMessage()
{
Console.WriteLine($"编号:{Id},姓名:{Name},地址:{Address},入职日期:{JoinDate}");
}
}
}
2).TestClass.cs的源程序如下:
using System;
namespace TestClassLibrary
{
/// <summary>
/// 测试类
/// </summary>
public class TestClass
{
/// <summary>
/// 加法
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
/// <returns></returns>
public static int Add(int x, int y = 2)
{
return x + y;
}
/// <summary>
/// 减法
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
/// <returns></returns>
public static int Subtract(int x, int y)
{
return x - y;
}
/// <summary>
/// 获取数组的最大数以及最大数所在的索引
/// </summary>
/// <param name="array">数组</param>
/// <param name="maxIndex">输出最大值的所在的索引</param>
/// <returns></returns>
public int GetMaxNumber(int[] array, out int maxIndex)
{
if (array == null || array.Length == 0)
{
Console.WriteLine("数组不能为null,数组的长度也不能为,暂定返回值为-1");
maxIndex = -1;
return -1;
}
int max = array[0];
maxIndex = 0;
for (int i = 1; i < array.Length; i++)
{
if (max < array[i])
{
maxIndex = i;
max = array[i];
}
}
return max;
}
/// <summary>
/// 获得不定项数组的长度
/// </summary>
/// <param name="array"></param>
/// <returns></returns>
public int GetVaryArrayLength(params int[] array)
{
if (array == null)
{
return 0;
}
return array.Length;
}
/// <summary>
/// 测试带ref的参数
/// </summary>
/// <param name="inParameter"></param>
/// <param name="refParameter"></param>
public void TestReference(int inParameter, ref int refParameter)
{
inParameter = 5;
refParameter = 2;
Console.WriteLine("参数默认为输入参数,如:inParameter,不会改变原来的值.\r\n带ref或者out的参数是引用参数,如:refParameter,可以改变原来的值.");
}
/// <summary>
/// 私有方法无法通过反射得到该方法的信息
/// </summary>
private void PrivateMethod()
{
Console.WriteLine("私有方法");
}
}
}
三、ReflectionDemo控制台的默认类Program用于测试反射调用相关信息,源程序如下:
using System;
using System.Reflection;
namespace ReflectionDemo
{
class Program
{
static void Main(string[] args)
{
Assembly assembly = Assembly.Load("TestClassLibrary");
Console.WriteLine($"程序集名称:{assembly.FullName}");
Type[] types = assembly.GetTypes();
for (int i = 0; i < types.Length; i++)
{
Console.WriteLine($"第【{i + 1}】个类型【{types[i].FullName}】,所有的方法列表如下:");
MethodInfo[] methodInfos = types[i].GetMethods();
for (int j = 0; j < methodInfos.Length; j++)
{
Console.WriteLine($" 第【{j + 1}】个方法【{methodInfos[j].Name}】.返回类型:{methodInfos[j].ReturnType},是静态方法:{methodInfos[j].IsStatic},是公共方法:{methodInfos[j].IsPublic}");
Console.WriteLine($" 方法【{methodInfos[j].ReturnType} {methodInfos[j].Name}】的参数如下:");
//方法所对应的参数信息:
ParameterInfo[] parameterInfos = methodInfos[j].GetParameters();
for (int k = 0; k < parameterInfos.Length; k++)
{
//方法的类型是引用类型时(带有"&"表示引用类型) 如:System.Int32&,此时参数带ref或out修饰
//如果参数是输出参数(paras[k].IsOut==true),则参数的修饰是out,否则是ref
Console.WriteLine($" 第【{k + 1}】个参数{parameterInfos[k].ParameterType} {parameterInfos[k].Name},是否输出参数:{parameterInfos[k].IsOut},是否存在默认值:{parameterInfos[k].HasDefaultValue},默认值:{parameterInfos[k].DefaultValue}");
}
}
Console.WriteLine();
}
Console.WriteLine("当我们知道方法的名称,返回值信息和参数信息时,就可以反射调用该方法或构造函数了.");
TestInvokeMethod();
Console.WriteLine("下面测试类的属性(get,set)信息...");
TestProperty();
Console.ReadLine();
}
/// <summary>
/// 测试调用类库中的方法
/// </summary>
static void TestInvokeMethod()
{
Type ty = Assembly.Load("TestClassLibrary").GetType(string.Format("{0}.{1}", "TestClassLibrary", "TestClass"));
Console.WriteLine("调用TestClassLibrary.TestClass 类的公共静态方法public static int Add(int x, int y=2) 的例子");
MethodInfo mi = ty.GetMethod("Add");
//调用静态方法Add时,Invoke的第一个参数为null
object returnValue = mi.Invoke(null, new object[] { 4, 5 });
Console.WriteLine("Add方法的返回值:{0}\r\n", returnValue);
Console.WriteLine("调用TestClassLibrary.TestClass 类的公共实例化方法public int GetMaxNumber(int[] array, out int maxIndex) 的例子");
MethodInfo mi1 = ty.GetMethod("GetMaxNumber");
//调用实例化方法(非静态方法)需要创建类型的一个实例
object instanceObject = Activator.CreateInstance(ty);
int maxIndex = -1;
object[] parametersInfo = new object[] { new int[] { 8, 20, 15, 36, 1, 4 }, maxIndex };
//调用实例化方法GetMaxNumber时,Invoke的第一个参数是一个实例化对象
object returnValue1 = mi1.Invoke(instanceObject, parametersInfo);
maxIndex = Convert.ToInt32(parametersInfo[1]);
Console.WriteLine("GetMaxNumber方法的返回值(最大值):{0},最大值的索引:{1}", returnValue1, maxIndex);
}
/// <summary>
/// 测试属性信息
/// </summary>
static void TestProperty()
{
Type type = Assembly.Load("TestClassLibrary").GetType(string.Format("{0}.{1}", "TestClassLibrary", "Employee"));
//调用实例化对象
object instanceObject = Activator.CreateInstance(type);
Console.WriteLine("propertyInfo.SetValue(类的实例化对象,当前属性对应类型的某个值)");
PropertyInfo[] propertyInfos = type.GetProperties();
for (int i = 0; i < propertyInfos.Length; i++)
{
PropertyInfo propertyInfo = propertyInfos[i];
Console.WriteLine($"属性名称:{propertyInfo.Name},属性类型:{propertyInfo.PropertyType},对应的特性:{string.Join(",", propertyInfo.CustomAttributes)}");
switch (propertyInfo.Name)
{
case "Id":
propertyInfo.SetValue(instanceObject, 123);
break;
case "Name":
propertyInfo.SetValue(instanceObject, "扁络桓");
break;
case "Address":
propertyInfo.SetValue(instanceObject, "驭界枢");
break;
case "JoinDate":
propertyInfo.SetValue(instanceObject, DateTime.Now.AddYears(-3));
break;
}
}
MethodInfo methodInfo = type.GetMethod("PrintMessage");
methodInfo.Invoke(instanceObject, null);
}
}
}
四、程序运行如图: