.Net 反射

.Net 反射

反射反射,程序员的快乐

说明

在一些常见的服务中,我们知道某些方法的名字,想要直接调用如何去做呢?
目前我知道的是委托和反射。但是委托出现了新的方法,还得手动去添加,反射则不一样了。
只要方法名规律保持一致,直接调用反射方法即可避免写无聊的逻辑。
当然,反射debug有些些许麻烦

获得实体的属性名称

   foreach (PropertyInfo propertyInfo in typeof(实体).GetProperties()) 
            {
                fields.Add(propertyInfo.Name);
            }

实体获得属性值

 var temp = 实体.GetType().GetProperty("属性").GetValue(实体, null);

实体赋值

  • 反射赋值遇到类型不一致,Object of type 'System.String' cannot be converted to type 'System.Int32
    • 解决
      property.SetValue(obj,Convert.ChangeType(value,property.PropertyType),null);//类型转换。

实体获取字段值

C#当中获取属性有种情况为,该属性没有get和set函数,则该属性非属性,实际为字段。因此需要使用以下方法来获取:

实体.GetType().GetFields() //查看有几个字段
实体.GetType().GetField("字段") //不为null则存在该字段
实体.GetType().GetField("字段").GetValue(实体) //获取字段值

获取私有方法

 class Program
    {
       
        private static void Main(string[] args)
        {
            //通过反射来调私有的成员
            Type type = typeof(Person);
            //BindingFlags类型枚举,BindingFlags.NonPublic | BindingFlags.Instance 组合才能获取到private私有方法
            MethodInfo methodInfo = type.GetMethod("SayHello", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);
            object obj = Activator.CreateInstance(type);  //通过反射类型创建实例对象
            methodInfo.Invoke(obj, null);

            Console.ReadKey();
        }
    }

    public class Person
    {
        private static  void SayHello()
        {
            Console.WriteLine("我是私有方法。");
            Console.ReadKey();
        }
    }

创建实体

  • 无构造函数 object obj = Activator.CreateInstance(type); //通过反射类型创建实例对象
  • 指定的构造函数,例如需要一个参数的构造函数。var client = Activator.CreateInstance(tmpType,new object[] { channel });

异步方法

  • invoke 转换为Task类型,await 等待完成,接着反射Task.Result的值
            var type = this.GetType();
            var methodList = type.GetMethods().Where(a => a.Name.StartsWith("GetExport") && a.Name.EndsWith("List")).ToList();
            foreach (var method in methodList)
            {
                var task = (Task)method.Invoke(this, null);
                await task;
                var val = task.GetType().GetProperty("Result").GetValue(task, null) as IEnumerable<object>;
                if (val != null)
                    workBook.Write(DisplayAttributeHelper.GetTable(val.ToList()));
            }

泛型方法

  • GetMethod获取泛型方法名称, MakeGenericMethod写入指定类型的参数(Type类型)。最后Invoke
                string binPath = Assembly.GetExecutingAssembly().Location;
                var assembly = Assembly.LoadFrom(binPath); //反射看这篇文章  https://www.cnblogs.com/zagelover/articles/2726034.html
                var allServiceList = assembly.GetTypes().Where(a => a.Namespace.StartsWith("DataTool.gRPC.Service")
                &&a.Name.EndsWith("Service")).ToList();
                allServiceList.ForEach(a =>
                {
                    var method = typeof(GrpcEndpointRouteBuilderExtensions).GetMethod("MapGrpcService").MakeGenericMethod(a);
                    method.Invoke(null, new[] { endpoints });
                });

静态类和非静态类

  • 静态类Invoke(null, new[] { endpoints }); todo 等待补充
  • 非静态类Invoke(this, null)

特性

  • CustomAttributes属性中的 AttributeType等于typeof(ObsoleteAttribute)
            //反射特性
            string binPath = Assembly.GetExecutingAssembly().Location;
            var assembly = Assembly.LoadFrom(binPath); //反射看这篇文章  https://www.cnblogs.com/zagelover/articles/2726034.html
            var methodList= assembly.GetType("DataTool.Demo.Program").GetMethods().ToList();
            var a1 = methodList.FirstOrDefault(a => a.Name == "Task1");
            //var b1 = a1.GetCustomAttribute<ObsoleteAttribute>();
            var aaa1= a1.CustomAttributes.Any(a => a.AttributeType ==typeof(ObsoleteAttribute));
  • 获取特性值

加载程序集

var assembly = Assembly.Load("DataTool.Model");

创建List<泛型>

  • 通过反射创建List泛型的话,后面只能通过反射该对象的方法去做。
             //创建List泛型对象结果,也可以通过反射实现`AddRange`,这边采用.ToList()
            //https://www.cnblogs.com/lovewl2/p/6582347.html
            //var result = (Activator.CreateInstance(typeof(List<>).MakeGenericType(new Type[] { entityType })) as IEnumerable<object>).ToList();
  • 可以直接var result = new List<object>();

.net core 依赖注入gRPC服务

  • 原本注入方式
            //先注入一个Mi服务实施
            services.AddTransient(a =>
            {
                var zz = a;

                AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);
                var baseGRPCUrl = AppSettingsHelper.Configuration["GRPCUrl"];
                var channel = GrpcChannel.ForAddress(baseGRPCUrl);
                return new MI.MIClient(channel);
            });
  • 反射注入。先注入构造函数所需对象,再注入构造函数的对象。
            //反射注入所有服务
            var assembly = Assembly.GetExecutingAssembly();
            var serviceList = assembly.GetTypes().Where(a => a.Namespace==("DataTool.WebApi.Controllers")
            &&a.GetMembers().Any(b=>b.Name.EndsWith("Client"))
            ).ToList(); //https://q.cnblogs.com/q/67716/  GetMembers

            AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);
            var baseGRPCUrl = AppSettingsHelper.Configuration["GRPCUrl"];
            var channel = GrpcChannel.ForAddress(baseGRPCUrl);
            //先注入gRPC构造函数所需对象
            services.AddTransient(a => {
                return channel;
            });
            serviceList.ForEach(a =>
            {
                var tmpType = a.GetMembers().First(b => b.Name.EndsWith("Client")) as Type;
                var client = Activator.CreateInstance(tmpType,new object[] { channel });
                services.AddTransient(tmpType,q1=> { return client; });
            });
原文地址:https://www.cnblogs.com/Alex-Mercer/p/15513709.html