ASP.NET Core C# 反射 & 表达式树 (第二篇)
前言
上一篇讲到了各种反射的操作方式, 这一篇主要说说如何找到类型.
Type Information
在找类型的时候, 除了依据简单的 string 以外, 还会用到很多类型属性来做判断.
比如它是不是 value type, 它是不是 Enum, 它是不是 interface, 它是不是继承了某一个类型.
常用到的识别
// is inherit other class
var yes1 = typeof(Dog).IsAssignableTo(typeof(Animal)); // true
var yes2 = typeof(Animal).IsAssignableFrom(typeof(Dog)); // true var yes3 = typeof(int).IsValueType; // true
var yes4 = typeof(string).IsValueType; // false
var yse5 = typeof(Enum1).IsEnum; // true
var yes6 = typeof(Interface1).IsInterface; // true // have generic ?
var yes7 = typeof(HaveGeneric<>).IsGenericType; // true
Is nullable string?
从 .NET 6 开始, 反射可以检查出是不是 nullable string 和 reference 了.
How to use .NET reflection to check for nullable reference type
var type = typeof(Person);
var context = new NullabilityInfoContext();
var nameProperty = type.GetProperty("Name")!;
var nameInfo = context.Create(nameProperty);
var isNullable = nameInfo.ReadState == NullabilityState.Nullable; // true
BindingFlags
BindingFlags 能在获取 properties, methods, fields, etc. 的时候, 指定 private, public, static, etc. 的范围.
比较常用到的

图片l来源: 详解 .NET 反射中的 BindingFlags 以及常用的 BindingFlags 使用方式
常用的方式
var constructors = type.GetConstructors(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static);
var properties = type.GetProperties();
var methods = type.GetMethods(); // 不包括 constructor
var fields = type.GetFields();
var members = type.GetMembers(); // 全部东西
默认就是 Public, Instance, Static
Property Info
一些常用到的 property info 判断
public class Person
{
public string Name1 { get; private set; } = ""; // setter is private
public string Name2 { private get; set; } = ""; // getter is private
public string Name3 { get; } = ""; // get only
public string Name4 { get; init; } = ""; // setter is init
// public string SetOnly { set; } = ""; // 报错, 不可以只有 set
// private string Name3 { public get; set; } // 报错, 前面 private 后面 public 是不行的
}
1. BindingFlags.Public, 只要前面是 public 就获取得到, setter 是 private 无所谓.
2.CanWrite
typeof(Person).GetProperty("Name1")!.CanWrite
除非完全没有 set, 要不然 CanWrite 就是 true, init 依然是 true.
3. GetSetMethod 可以用来判断是不是 private, 参考: How to check if property setter is public
var t1 = typeof(Person).GetProperty("Name1")!.GetSetMethod(); // null
var t2 = typeof(Person).GetProperty("Name2")!.GetSetMethod(); // ok
var t3 = typeof(Person).GetProperty("Name3")!.GetSetMethod(); // null
var t4 = typeof(Person).GetProperty("Name4")!.GetSetMethod(); // ok
var person = Activator.CreateInstance(typeof(Person));
typeof(Person).GetProperty("Name1")!.SetValue(person, "dada"); // ok
typeof(Person).GetProperty("Name2")!.SetValue(person, "dada"); // ok
typeof(Person).GetProperty("Name3")!.SetValue(person, "dada"); // error, can't set
typeof(Person).GetProperty("Name4")!.SetValue(person, "dada"); // ok
Generic 高级
var type = typeof(Animal<,>);
var yes = type.IsGenericType; // 虽然还没有填充内容, 它依旧是一个 GenericType
var yes1 = type.ContainsGenericParameters; // 表示它还没有填充内容 (虽然字面意思好像是反过来 /.\, 但总之 true 就表示还没有 MakeGenericType 就对了...)
type.MakeGenericType(new Type[] { typeof(string), typeof(int) });
var yes2 = type.ContainsGenericParameters; // 依然是 true, 因为填充不是 void method
var newType = type.MakeGenericType(new Type[] { typeof(string), typeof(int) });
var no = newType.ContainsGenericParameters; // false, 这就表示已经有填充内容了.
var yes3 = type == typeof(Animal<,>); // yes
var yes4 = newType == typeof(Animal<string,int>); // yes
var yes5 = newType.GetGenericTypeDefinition() == typeof(Animal<,>); // yes 通过 GetGenericTypeDefinition 可以返回还没填充的类型
上一篇只是讲了简单的导入,导出. 这篇补上一些其它小细节.
1. MakeGenericType 不是 void method 哦
2. ContainsGenericParameters = true 表示这个 type 还没有被填充 MakeGenericType, false 表示已经有内容了.

3. IsGenericType 不管有没有内容, 只要是 Generic 就是 true
4. GetGenericTypeDefinition 返回还没有填充的 Generic Type
Class has implement some interface?
要判断一个 class 是否有 implement 某个 interface, 最好的方式就是拿这个 class type 的所有 interfaces 出来对比
/// <summary>
/// check if class implement interface
/// </summary>
/// <param name="classType"></param>
/// <param name="interfaceType">if interface is empty generic [,] then class will use empty generic too for compare, if not then == compare</param>
/// <returns></returns>
public static bool HasImplementInterface(Type classType, Type interfaceType)
{
var requireIsGenericType = interfaceType.IsGenericType;
var requireIsEmptyGeneric = interfaceType.ContainsGenericParameters; // is empty <,> ?
return classType.GetInterfaces().Where(classInterface =>
{
if (requireIsGenericType && requireIsEmptyGeneric)
{
if (!classInterface.IsGenericType) return false;
return classInterface.GetGenericTypeDefinition() == interfaceType;
}
else
{
return classInterface == interfaceType;
}
}).Any();
}
注: 这里是判断 Type, 如果是实例, 直接 object is Interface 就可以了, 不过那个就不是反射了.
Get Right Overload Method
当方法有重载的时候, 就不可以仅仅通过方法名来获取到正确的方法.
需要判断它的 Generic, 还有它的 Parameters 类型
public static MethodInfo GetMethod(Type classType, string methodName, List<Type> genericTypes = null!, List<Type> parameterTypes = null!)
{
genericTypes ??= new();
parameterTypes ??= new();
return classType.GetMethods()
.Where(
m => m.Name == methodName &&
m.GetGenericArguments().Length == genericTypes.Count &&
m.GetParameters().Length == parameterTypes.Count
)
.Select(m => genericTypes.Count > 0 ? m.MakeGenericMethod(genericTypes.ToArray()) : m)
.Single(m => m.GetParameters().Select(p => p.ParameterType).SequenceEqual(parameterTypes));
}
首先是 name, generic count, parameter count 要对
然后把 generic type 填充进去 method type, 然后才可以对比 parameters.
因为 generic 可能就会用到 parameter 上, 如果没有填充好的话, 对比 parameter type 就会错了.
Get Right Overload Constructor
public static ConstructorInfo GetConstructor(Type classType, List<Type> paramTypes = null!)
{
paramTypes ??= new();
return classType.GetConstructors()
.Where(m => m.GetParameters().Length == paramTypes.Count)
.Single(m => m.GetParameters().Select(p => p.ParameterType).SequenceEqual(paramTypes));
}
这个就比较简单, 因为 Constructor 不会有 Generic, 有 Generic 的是它的 Class
总结
到这里, 反射就算有个基本功了. 下一篇来看看表达式树.
ASP.NET Core C# 反射 & 表达式树 (第二篇)的更多相关文章
- ASP.NET Core中使用表达式树创建URL
当我们在ASP.NET Core中生成一个action的url会这样写: var url=_urlHelper.Action("Index", "Home"); ...
- 使用Asp.Net Core MVC 开发项目实践[第二篇:EF Core]
在项目中使用EF Core还是比较容易的,在这里我们使用的版本是EF Core 2.2. 1.使用nuget获取EF Core包 这个示例项目使用的是SQLSERVER,所以还需要下载Microsof ...
- ASP.NET自定义控件组件开发 第一章 第二篇 接着待续
原文:ASP.NET自定义控件组件开发 第一章 第二篇 接着待续 ASP.NET自定义控件组件开发 第一章 第二篇 接着待续 很感谢大家给我的第一篇ASP.NET控件开发的支持!在写这些之前,我也看了 ...
- Pro ASP.NET Core MVC 第6版 第二章(后半章)
增加动态输出 整个web应用平台的关注点在于构建并显示动态输出内容.在MVC里,控制器负责构建一些数据并将其传给视图.视图负责渲染成HTML. 从控制器向视图传递数据的一种方式是使用ViewBag 对 ...
- Pro ASP.NET Core MVC 第6版 第二章(前半章)
目录 第二章 第一个MVC 应用程序 学习一个软件开发框架的最好方法是跳进他的内部并使用它.在本章,你将用ASP.NET Core MVC创建一个简单的数据登录应用.我将它一步一步地展示,以便你能看清 ...
- C# 反射 表达式树 模糊搜索
反射实体T,非datetime字段反射获取表达式树 public static Expression<Func<T, bool>> GetSearchExpression& ...
- ASP.NET Core管道深度剖析[共4篇]
之所以称ASP.NET Core是一个Web开发平台,源于它具有一个极具扩展性的请求处理管道,我们可以通过这个管道的定制来满足各种场景下的HTTP处理需求.ASP. NET Core应用的很多特性,比 ...
- 使用Asp.Net Core MVC 开发项目实践[第一篇:项目结构说明]
先从下图看整体项目结构: Mango.Manager: 为后台管理项目 Mango.Web: 为前台项目 Mango.Framework.Core: 为常用的基础操作类项目 Mango.Framewo ...
- 了解ASP.NET Core 依赖注入,看这篇就够了 于2017年11月6日由jesseliu发布
DI在.NET Core里面被提到了一个非常重要的位置, 这篇文章主要再给大家普及一下关于依赖注入的概念,身边有工作六七年的同事还个东西搞不清楚.另外再介绍一下.NET Core的DI实现以及对实例 ...
- 了解ASP.NET Core 依赖注入,看这篇就够了
DI在.NET Core里面被提到了一个非常重要的位置, 这篇文章主要再给大家普及一下关于依赖注入的概念,身边有工作六七年的同事还个东西搞不清楚.另外再介绍一下.NET Core的DI实现以及对实例 ...
随机推荐
- 推荐几款.NET开源且功能强大的实用工具,助你提高工作开发效率!
前言 俗话说得好"工欲善其事,必先利其器",今天大姚给大家推荐8款.NET开源且功能强大的实用工具,助你提高工作开发效率! DevToys 一款基于C#开源(MIT License ...
- 记一次在openEuler系统下离线编译升级到openssh9.8p1
缘起 由于某个项目上甲方对服务器进行漏洞扫描,系统为:openEuler 22.03 (LTS-SP4).提示现有OpenSSH版本存在漏洞,需要升级到openssh-9.8p1的版本(目前最新),遂 ...
- 一次url请求全过程
一次url请求全过程 1,从宏观总体来看url请求全流程 2,从家庭实际网络架构来看一看网络是如何搭建和传输的 3,从网络七层协议的角度来看一看网络在各个层次之间的传输过程 4,从三次握手四次挥手的角 ...
- 树莓派3b+ 安装Ubuntu mate18.04系统 配置SSH 、 远程桌面realvnc
Ubuntu mate for 树莓派3b+ 系统下载: 下载地址: https://ubuntu-mate.org/download/ 这里用32位系统:(64位也可以的,虽然还是实验阶段的,不 ...
- model.train方法的dataset_sink_mode参数设置为False时以step作为单位打印数据——(只在mode=context.GRAPH_MODE下成立,在mode=context.PYNATIVE_MODE模式下不成立)
如题: 官方中的内容支持: https://www.mindspore.cn/tutorial/training/zh-CN/r1.2/advanced_use/summary_record.html ...
- 社区6月月报 | Apache DolphinScheduler重要修复和优化记录
各位热爱Apache DolphinScheduler的小伙伴们,社区6月月报更新啦!这里将记录Apache DolphinScheduler社区每月的重要更新,欢迎关注. 月度Merge Stars ...
- 前端黑科技:使用 JavaScript 实现网页扫码功能
在数字化时代,二维码已经渗透到我们生活的方方面面.从移动支付到产品溯源,二维码凭借其便捷性和高效性,成为了信息传递的重要载体.而随着前端技术的不断发展,我们甚至可以使用 JavaScript 在网页端 ...
- 使用 navigateTo 实现灵活的路由导航
title: 使用 navigateTo 实现灵活的路由导航 date: 2024/8/13 updated: 2024/8/13 author: cmdragon excerpt: 摘要:本文详细介 ...
- curl可以访问虚拟机资源,但是宿主机浏览器不能访问
如果想从宿主机访问到虚拟机内的php,需要关闭宿主机的代理,并且设置虚拟机内的防火墙不要屏蔽宿主机的ip. 设置虚拟机防火墙方法: 查找宿主机IP:win+r,输入ipconfig 打开虚拟机,输入s ...
- Linux嵌入式所有知识点-思维导图-【一口君吐血奉献】
一.前言 很多粉丝问我,我的Linux和嵌入式当初是如何学习的? 其实彭老师在最初学习的过程中,走了相当多的弯路: 有些可以不学的花了太多的时间去啃 有些作为基础必须优先学习的,却忽略了, 结果工作中 ...