文章目录
前言
我上篇文章已经基本解决了反射的基本问题,现在只留下了一乌云,就是Json化对象如何转化为MethodInfo 的参数入参
但是反射的问题还有一朵解决不了的乌云,Json字符串参数入参MethodInfo。
直接运行MethodInfo
我们直接写一个简单的函数
csharp
/// <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 }));
}
csharp
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实例化
csharp
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();
}
运行结果
无法实例化问题部分参数的问题
简单来说,有些对象就是无法实例化的,默认只能为Null,
Json反序列化
但是我感觉我想的有点多了,我直接把Json对象拆分了不就行了。
但是Json反序列化有个问题,你必须要告诉他这个类是什么,他才能反序列化。就是我们要通过ParamterInfos给出反序列化的模型
TypeConverter.ConvertTo 方法
是否将Dictionary<string、object>转换为匿名对象?
因为Method.invoke必须参数的类型一致,而我默认直接转为Object类型,是有点问题的。
经过长达一天的研究,我终于完全的解决的了
安装Json序列化工具
实战思路
初步序列化 Json Dictionary字典 MethodInfo ParametersInfos 找到Name,Type,Value 对找到的object类型的Value重新序列化,因为有歧义,比如int32和int64序列化之后都是一个值 将重新赋值成功的值放在一个数组里面 MethodInfo.Invoke对应参数
方法
csharp
/// <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);
}
测试用例
csharp
namespace NetCore.Models
{
public class T_Person
{
public string Name { get;set; }
public int Age { get; set; }
public string Sex { get; set; }
}
}
csharp
/// <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 }));
}
运行测试
csharp
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();
}
运行结果
代码总结
这个和我之前的特性的方法放在了一起
csharp
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实战的一些问题。