C# 反射的乌云,MethodInfo的Json序列化参数入参问题

文章目录

  • 前言
  • 直接运行MethodInfo
    • 运行结果
  • Json解决
    • ParamterInfo实例化
      • 运行结果
      • 无法实例化问题部分参数的问题
    • Json反序列化
  • 经过长达一天的研究,我终于完全的解决的了
    • 实战思路
    • 方法
    • 测试用例
    • 运行测试
    • 运行结果
  • 代码总结
  • 总结

前言

我上篇文章已经基本解决了反射的基本问题,现在只留下了一乌云,就是Json化对象如何转化为MethodInfo 的参数入参

C# 反射的终点:Type,MethodInfo,PropertyInfo,ParameterInfo,Summry

但是反射的问题还有一朵解决不了的乌云,Json字符串参数入参MethodInfo。

直接运行MethodInfo

我们直接写一个简单的函数

C# 反射的乌云,MethodInfo的Json序列化参数入参问题_第1张图片

        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        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(typeof(SwitchService));
     Console.WriteLine("运行完成!");
     Console.ReadKey();
 }

运行结果

C# 反射的乌云,MethodInfo的Json序列化参数入参问题_第2张图片

无法实例化问题部分参数的问题

Activator can’t create array and string?

C# 反射的乌云,MethodInfo的Json序列化参数入参问题_第3张图片
C# 反射的乌云,MethodInfo的Json序列化参数入参问题_第4张图片
简单来说,有些对象就是无法实例化的,默认只能为Null,

Json反序列化

但是我感觉我想的有点多了,我直接把Json对象拆分了不就行了。

但是Json反序列化有个问题,你必须要告诉他这个类是什么,他才能反序列化。就是我们要通过ParamterInfos给出反序列化的模型

TypeConverter.ConvertTo 方法

是否将Dictionary转换为匿名对象?

因为Method.invoke必须参数的类型一致,而我默认直接转为Object类型,是有点问题的。

Error : Object must implement IConvertible

经过长达一天的研究,我终于完全的解决的了

安装Json序列化工具
在这里插入图片描述

实战思路

初步序列化
Json
Dictionary字典
MethodInfo
ParametersInfos
找到Name,Type,Value
对找到的object类型的Value重新序列化,因为有歧义,比如int32和int64序列化之后都是一个值
将重新赋值成功的值放在一个数组里面
MethodInfo.Invoke对应参数

方法

/// 
/// Json对象入参
/// 
/// 实例化对象
/// 方法
/// 序列化参数
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; }
    }
}
        /// 
        /// 测试反序列化的方法
        /// 
        /// 
        /// 
        /// 
        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# 反射的乌云,MethodInfo的Json序列化参数入参问题_第5张图片

代码总结

C#高级语法 Attribute特性详解和类型,方法,变量附加特性讲解

这个和我之前的特性的方法放在了一起

   public static class MyAttributeHelper
   {

       /// 
       /// 获取该类型下所有的带Attribute的方法
       /// 
       /// 
       /// 
       /// 
       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;
       }

       /// 
       /// 获取该类型下所有的带Attribute的属性
       /// 
       /// 
       /// 
       /// 
       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;
       }
       /// 
       /// 获取程序集所有有T特性的类型class
       /// 
       /// 
       /// 
       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;
       }
       /// 
       /// 获取特性
       /// 
       /// 
       /// 
       /// 
       public static T GetAttribute<T>(Type type) where T : Attribute, new()
       {
           var res = new T();
           res = type.GetCustomAttribute<T>();
           return res;
       }

       /// 
       /// 获取特性
       /// 
       /// 
       /// 
       /// 
       public static T GetAttribute<T>(MethodInfo type) where T : Attribute, new()
       {
           var res = new T();
           res = type.GetCustomAttribute<T>();
           return res;
       }

       /// 
       /// 获取特性
       /// 
       /// 
       /// 
       /// 
       public static T GetAttribute<T>(PropertyInfo type) where T : Attribute, new()
       {
           var res = new T();
           res = type.GetCustomAttribute<T>();
           return res;
       }

       /// 
       /// 返回带有Attribute的类型元祖列表
       /// 
       /// 
       /// 
       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;
       }

       /// 
       /// 返回带有Attribute的变量元祖列表
       /// 
       /// 
       /// 
       /// 
       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;
       }

       /// 
       /// 返回带有Attribute的方法元祖列表
       /// 
       /// 
       /// 
       /// 
       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;
       }

       /// 
       /// Json对象入参
       /// 
       /// 实例化对象
       /// 方法
       /// 序列化参数
       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实战的一些问题。

你可能感兴趣的:(C#,c#,json,开发语言)