文章目录
- 前言
- 直接运行MethodInfo
- 运行结果
- Json解决
- ParamterInfo实例化
- 运行结果
- 无法实例化问题部分参数的问题
- Json反序列化
- 经过长达一天的研究,我终于完全的解决的了
- 实战思路
- 方法
- 测试用例
- 运行测试
- 运行结果
- 代码总结
- 总结
前言
我上篇文章已经基本解决了反射的基本问题,现在只留下了一乌云,就是Json化对象如何转化为MethodInfo 的参数入参
C# 反射的终点:Type,MethodInfo,PropertyInfo,ParameterInfo,Summry
但是反射的问题还有一朵解决不了的乌云,Json字符串参数入参MethodInfo。
直接运行MethodInfo
我们直接写一个简单的函数
/// <summary>/// /// </summary>/// <param name="age"></param>/// <param name="name"></param>/// <param name="person"></param>public void TestParamters(int age, string name, T_Person person){Console.WriteLine(JsonConvert.SerializeObject(new { age = age, name = name, person = person }));}
static void Main(string[] args)
{//从程序集中拿出SwitchService switchService = new SwitchService();var method = typeof(SwitchService).GetMethod("TestParamters");if (method != null){//默认方法method.Invoke(switchService, new object[] { 15, "小天", new T_Person() });}Console.WriteLine("运行完成!");Console.ReadKey();
}
运行结果
这个是非常好解决的,但是有个问题,我们运行反射的时候根本不知道如何入参的个数和类型。我们还需要解决Json到Paramters的问题
Json解决
ParamterInfo实例化
static void Main(string[] args){//从程序集中拿出SwitchService switchService = new SwitchService();var method = typeof(SwitchService).GetMethod("TestParamters");//需要反序列化的字符串var paramterStr = @"{""age"":0,""name"":null,""person"":{""Name"":null,""Age"":0,""Sex"":null}}";if (method != null){//默认方法method.Invoke(switchService, new object[] { 15, "小天", new T_Person() });var parameterInfos = method.GetParameters();object[] methodParams = new object[parameterInfos.Length];for (int i = 0; i < parameterInfos.Length; i++){var item = parameterInfos[i];//通过程序集创建实例化对象Type itemType = item.ParameterType;try{//无法实例化无默认构造函数的方法methodParams[i] = System.Activator.CreateInstance(itemType, true);}catch (Exception ex){Console.WriteLine(ex.ToString());}}method.Invoke(switchService, methodParams);//method.Invoke(switchService, new object[] { paramterStr });}//var methods = MyAttributeHelper.GetAllMethods<MySwitchAttribute>(typeof(SwitchService));Console.WriteLine("运行完成!");Console.ReadKey();}
运行结果
无法实例化问题部分参数的问题
Activator can’t create array and string?
简单来说,有些对象就是无法实例化的,默认只能为Null,
Json反序列化
但是我感觉我想的有点多了,我直接把Json对象拆分了不就行了。
但是Json反序列化有个问题,你必须要告诉他这个类是什么,他才能反序列化。就是我们要通过ParamterInfos给出反序列化的模型
TypeConverter.ConvertTo 方法
是否将Dictionary<string、object>转换为匿名对象?
因为Method.invoke必须参数的类型一致,而我默认直接转为Object类型,是有点问题的。
Error : Object must implement IConvertible
经过长达一天的研究,我终于完全的解决的了
安装Json序列化工具
实战思路
方法
/// <summary>
/// Json对象入参
/// </summary>
/// <param name="obj">实例化对象</param>
/// <param name="methodInfo">方法</param>
/// <param name="JsonStr">序列化参数</param>
public static void MethodInfoInvokeJson(object obj ,MethodInfo methodInfo,string JsonStr)
{//获取所有的入参的信息var parametersInfos = methodInfo.GetParameters();//即将入参的对应变量var methodParams = new object[parametersInfos.Length];//反序列化的Json数据var deserializeValues = JsonConvert.DeserializeObject<Dictionary<string, object>>(JsonStr);//找到对应的Json参数for (var i = 0; i < parametersInfos.Length; i++){var parameter = parametersInfos[i];Type parameterType = parameter.ParameterType;//如果存在Key,则取出改值if (deserializeValues.ContainsKey(parameter.Name)){object parameterValue = deserializeValues[parameter.Name];//需要重新序列化对象parameterValue = JsonConvert.DeserializeObject(JsonConvert.SerializeObject(parameterValue), parameterType);methodParams[i] = parameterValue;}}methodInfo.Invoke(obj, methodParams);
}
测试用例
namespace NetCore.Models
{public class T_Person{public string Name { get;set; }public int Age { get; set; }public string Sex { get; set; }}
}
/// <summary>/// 测试反序列化的方法/// </summary>/// <param name="age"></param>/// <param name="name"></param>/// <param name="person"></param>public void TestParamters( int age, string name, T_Person person){Console.WriteLine(JsonConvert.SerializeObject(new { age = age, name = name, person = person }));}
运行测试
static void Main(string[] args){//从程序集中拿出SwitchService switchService = new SwitchService();var method = typeof(SwitchService).GetMethod("TestParamters");//需要反序列化的字符串var paramterStr = @"{""age"":0,""name"":""小刘"",""person"":{""Name"":null,""Age"":0,""Sex"":null}}";try{//执行序列化方法MethodInfoInvokeJson(switchService, method, paramterStr); }catch (Exception ex){Console.WriteLine(ex.ToString());}Console.WriteLine("运行完成!");Console.ReadKey();}
运行结果
代码总结
C#高级语法 Attribute特性详解和类型,方法,变量附加特性讲解
这个和我之前的特性的方法放在了一起
public static class MyAttributeHelper{/// <summary>/// 获取该类型下所有的带Attribute的方法/// </summary>/// <typeparam name="T"></typeparam>/// <param name="type"></param>/// <returns></returns>public static List<MethodInfo> GetAllMethods<T>(Type type) where T : class, new(){var res = new List<MethodInfo>();res = type.GetMethods().Where(t => t.GetCustomAttributes(typeof(T), false).Any()).ToList();return res;}/// <summary>/// 获取该类型下所有的带Attribute的属性/// </summary>/// <typeparam name="T"></typeparam>/// <param name="type"></param>/// <returns></returns>public static List<PropertyInfo> GetAllPropertys<T>(Type type) where T : class, new(){var res = new List<PropertyInfo>();res = type.GetProperties().Where(t => t.GetCustomAttributes(typeof(T), false).Any()).ToList();return res;}/// <summary>/// 获取程序集所有有T特性的类型class/// </summary>/// <typeparam name="T"></typeparam>/// <returns></returns>public static List<Type> GetAllTypes<T>() where T : Attribute{var res = new List<Type>();//Assembly存放所有的程序集res = Assembly.GetExecutingAssembly().GetTypes().Where(t => t.GetCustomAttributes(typeof(T), false).Any())//我们找到所有程序集中带有T特性的Type类型.ToList();return res;}/// <summary>/// 获取特性/// </summary>/// <typeparam name="T"></typeparam>/// <param name="model"></param>/// <returns></returns>public static T GetAttribute<T>(Type type) where T : Attribute, new(){var res = new T();res = type.GetCustomAttribute<T>();return res;}/// <summary>/// 获取特性/// </summary>/// <typeparam name="T"></typeparam>/// <param name="model"></param>/// <returns></returns>public static T GetAttribute<T>(MethodInfo type) where T : Attribute, new(){var res = new T();res = type.GetCustomAttribute<T>();return res;}/// <summary>/// 获取特性/// </summary>/// <typeparam name="T"></typeparam>/// <param name="model"></param>/// <returns></returns>public static T GetAttribute<T>(PropertyInfo type) where T : Attribute, new(){var res = new T();res = type.GetCustomAttribute<T>();return res;}/// <summary>/// 返回带有Attribute的类型元祖列表/// </summary>/// <typeparam name="Att"></typeparam>/// <returns></returns>public static List<(Type type, Att att)> GetAll_TypeAndAtt<Att>() where Att : Attribute, new(){var res = new List<(Type type, Att att)> ();var typeLists = GetAllTypes<Att>();foreach (var item in typeLists){var att = GetAttribute<Att>(item);res.Add((item, att)); }return res;}/// <summary>/// 返回带有Attribute的变量元祖列表/// </summary>/// <typeparam name="Att"></typeparam>/// <param name="type"></param>/// <returns></returns>public static List<(PropertyInfo property, Att att)> GetAll_PropertyAndAtt<Att>(Type type) where Att : Attribute, new(){var res = new List<(PropertyInfo type, Att att)>();var typeLists = GetAllPropertys<Att>(type);foreach (var item in typeLists){var att = GetAttribute<Att>(item);res.Add((item, att));}return res;}/// <summary>/// 返回带有Attribute的方法元祖列表/// </summary>/// <typeparam name="Att"></typeparam>/// <param name="type"></param>/// <returns></returns>public static List<(MethodInfo method, Att att)> GetAll_MethodAndAtt<Att>(Type type) where Att : Attribute, new(){var res = new List<(MethodInfo type, Att att)>();var typeLists = GetAllMethods<Att>(type);foreach (var item in typeLists){var att = GetAttribute<Att>(item);res.Add((item, att));}return res;}/// <summary>/// Json对象入参/// </summary>/// <param name="obj">实例化对象</param>/// <param name="methodInfo">方法</param>/// <param name="JsonStr">序列化参数</param>public static void MethodInfoInvokeJson(object obj, MethodInfo methodInfo, string JsonStr){//获取所有的入参的信息var parametersInfos = methodInfo.GetParameters();//即将入参的对应变量var methodParams = new object[parametersInfos.Length];//反序列化的Json数据var deserializeValues = JsonConvert.DeserializeObject<Dictionary<string, object>>(JsonStr);//找到对应的Json参数for (var i = 0; i < parametersInfos.Length; i++){var parameter = parametersInfos[i];Type parameterType = parameter.ParameterType;//如果存在Key,则取出改值if (deserializeValues.ContainsKey(parameter.Name)){object parameterValue = deserializeValues[parameter.Name];//需要重新序列化对象parameterValue = JsonConvert.DeserializeObject(JsonConvert.SerializeObject(parameterValue), parameterType);methodParams[i] = parameterValue;}}methodInfo.Invoke(obj, methodParams);}}
总结
我经过一天的研究,终于解决了这个Json化对象这朵反射的乌云。但是如果要和Attribute联合使用,那么就要用到传说中的IOC容器了。接下来我会解决一下Attrbute实战的一些问题。