.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; });
});