当前位置: 首页 > news >正文

详解 .NET 反射中的 BindingFlags 以及常用的 BindingFlags 使用方式

使用 .NET 的反射 API 时,通常会要求我们传入一个 BindingFlags 参数用于指定反射查找的范围。不过如果对反射不熟的话,第一次写反射很容易写错导致找不到需要的类型成员。

本文介绍 BindingFlags 中的各个枚举标记的含义、用途,以及常用的组合使用方式。


本文内容

    • 所有的 BindingFlags
      • 默认值
      • 查找
      • 调用
      • 其他
    • 你可能会有的疑问
    • 常用的组合
    • 附 BindingFlags 的源码

所有的 BindingFlags

默认值

// 默认值
Default

查找

这些标记用于反射的时候查找类型成员:

// 表示查找的时候,需要忽略大小写。
IgnoreCase

// 仅查找此特定类型中声明的成员,而不会包括这个类继承得到的成员。
DeclaredOnly

// 仅查找类型中的实例成员。
Instance

// 仅查找类型中的静态成员。
Static

// 仅查找类型中的公共成员。
Public

// 仅查找类型中的非公共成员(internal protected private)
NonPublic

// 会查找此特定类型继承树上得到的静态成员。但仅继承公共(public)静态成员和受保护(protected)静态成员;不包含私有静态成员,也不包含嵌套类型。
FlattenHierarchy

调用

这些标记用于为 InvokeMember 方法提供参数,告知应该如何反射调用一个方法:

// 调用方法。
InvokeMethod

// 创建实例。
CreateInstance

// 获取字段的值。
GetField

// 设置字段的值。
SetField

// 获取属性的值。
GetProperty

// 设置属性的值。
SetProperty

其他

接下来下面的部分就不是那么常用的了。

这些标记用于为 InvokeMember 方法提供参数,但是仅在调用一个 COM 组件的时候才应该使用:

PutDispProperty
PutRefDispProperty
ExactBinding
SuppressChangeType
OptionalParamBinding

下面是一些杂项……

// 忽略返回值(在 COM 组件的互操作中使用)
IgnoreReturn

// 反射调用方法时如果出现了异常,通常反射会用 TargetInvocationException 包装这个异常。
// 此标记用于禁止把异常包装到 TargetInvocationException 中。
DoNotWrapExceptions

你可能会有的疑问

  1. 如果 A 程序集对 B 程序集内部可见(InternalsVisibleTo("B")),那么 B 在反射查找 A 的时候,internal 成员的查找应该使用 Public 还是 NonPublic 标记呢?
    • 依然是 NonPublic 标记。
    • 因为反射的是程序集的元数据,这是静态的数据,跟运行时状态是无关的。

常用的组合

从上面的解释中可以发现,这个类型的设计其实是有问题的,不符合单一职责原则。所以我们会在不同的使用场景下使用不同区域的组合。

查找,也就是获取一个类型中的字段、属性、方法等的时候使用的。

拿到所有成员:

BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance

实际上 RuntimeReflectionExtensions.Everything 属性就是这么写的。

拿到公有的实例成员:

BindingFlags.Public | BindingFlags.Instance

附 BindingFlags 的源码

[Flags]
public enum BindingFlags
{
    // NOTES: We have lookup masks defined in RuntimeType and Activator.  If we
    //    change the lookup values then these masks may need to change also.

    // a place holder for no flag specifed
    Default = 0x00,

    // These flags indicate what to search for when binding
    IgnoreCase = 0x01,          // Ignore the case of Names while searching
    DeclaredOnly = 0x02,        // Only look at the members declared on the Type
    Instance = 0x04,            // Include Instance members in search
    Static = 0x08,              // Include Static members in search
    Public = 0x10,              // Include Public members in search
    NonPublic = 0x20,           // Include Non-Public members in search
    FlattenHierarchy = 0x40,    // Rollup the statics into the class.

    // These flags are used by InvokeMember to determine
    // what type of member we are trying to Invoke.
    // BindingAccess = 0xFF00;
    InvokeMethod = 0x0100,
    CreateInstance = 0x0200,
    GetField = 0x0400,
    SetField = 0x0800,
    GetProperty = 0x1000,
    SetProperty = 0x2000,

    // These flags are also used by InvokeMember but they should only
    // be used when calling InvokeMember on a COM object.
    PutDispProperty = 0x4000,
    PutRefDispProperty = 0x8000,

    ExactBinding = 0x010000,    // Bind with Exact Type matching, No Change type
    SuppressChangeType = 0x020000,

    // DefaultValueBinding will return the set of methods having ArgCount or 
    //    more parameters.  This is used for default values, etc.
    OptionalParamBinding = 0x040000,

    // These are a couple of misc attributes used
    IgnoreReturn = 0x01000000,  // This is used in COM Interop
    DoNotWrapExceptions = 0x02000000, // Disables wrapping exceptions in TargetInvocationException
}

参考资料

  • BindingFlags.cs
  • RuntimeReflectionExtensions.cs

我的博客会首发于 https://blog.walterlv.com/,而 CSDN 会从其中精选发布,但是一旦发布了就很少更新。

如果在博客看到有任何不懂的内容,欢迎交流。我搭建了 dotnet 职业技术学院 欢迎大家加入。

知识共享许可协议

本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。欢迎转载、使用、重新发布,但务必保留文章署名吕毅(包含链接:https://walterlv.blog.csdn.net/),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请与我联系。

相关文章:

  • 在 csproj 文件中使用系统环境变量的值(示例将 dll 生成到 AppData 目录下)
  • git subtree 的使用
  • 让你的 VSCode 具备调试 C# 语言 .NET Core 程序的能力
  • 手工编辑 tasks.json 和 launch.json,让你的 VSCode 具备调试 .NET Core 程序的能力
  • C#/.NET 如何结束掉一个进程
  • C#/.NET 移动或重命名一个文件夹(如果存在,则合并而不是出现异常报错)
  • 如何创建应用程序清单文件 App.Manifest,如何创建不带清单的应用程序
  • 应用程序清单 Manifest 中各种 UAC 权限级别的含义和效果
  • 启用 Windows 审核模式(Audit Mode),以 Administrator 账户来设置电脑的开箱体验
  • Windows 中的 UAC 用户账户控制
  • Windows 下使用 runas 命令以指定的权限启动一个进程(非管理员、管理员)
  • Windows 的 UAC 设置中的通知等级实际上只有两个档而已
  • Windows 系统上使用任务管理器查看进程的各项属性(命令行、DPI、管理员权限等)
  • C#/.NET 如何获取一个异常(Exception)的关键特征,用来判断两个异常是否表示同一个异常
  • C#/.NET 如何在第一次机会异常 FirstChanceException 中获取比较完整的异常堆栈
  • 【从零开始安装kubernetes-1.7.3】2.flannel、docker以及Harbor的配置以及作用
  • 10个确保微服务与容器安全的最佳实践
  • Docker下部署自己的LNMP工作环境
  • Git 使用集
  • javascript面向对象之创建对象
  • Linux CTF 逆向入门
  • Promise面试题,控制异步流程
  • puppeteer stop redirect 的正确姿势及 net::ERR_FAILED 的解决
  • Shell编程
  • VuePress 静态网站生成
  • 阿里云前端周刊 - 第 26 期
  • 解析带emoji和链接的聊天系统消息
  • 爬虫进阶 -- 神级程序员:让你的爬虫就像人类的用户行为!
  • 浅析微信支付:申请退款、退款回调接口、查询退款
  • 使用阿里云发布分布式网站,开发时候应该注意什么?
  • 事件委托的小应用
  • 思考 CSS 架构
  • 一天一个设计模式之JS实现——适配器模式
  • 函数计算新功能-----支持C#函数
  • 支付宝花15年解决的这个问题,顶得上做出十个支付宝 ...
  • # 日期待t_最值得等的SUV奥迪Q9:空间比MPV还大,或搭4.0T,香
  • $().each和$.each的区别
  • $forceUpdate()函数
  • (1)SpringCloud 整合Python
  • (1)安装hadoop之虚拟机准备(配置IP与主机名)
  • (14)Hive调优——合并小文件
  • (16)Reactor的测试——响应式Spring的道法术器
  • (2.2w字)前端单元测试之Jest详解篇
  • (3)选择元素——(14)接触DOM元素(Accessing DOM elements)
  • (附源码)php新闻发布平台 毕业设计 141646
  • (附源码)流浪动物保护平台的设计与实现 毕业设计 161154
  • (简单有案例)前端实现主题切换、动态换肤的两种简单方式
  • (免费分享)基于springboot,vue疗养中心管理系统
  • (三)uboot源码分析
  • (三分钟了解debug)SLAM研究方向-Debug总结
  • (十)DDRC架构组成、效率Efficiency及功能实现
  • (转)大道至简,职场上做人做事做管理
  • (转)真正的中国天气api接口xml,json(求加精) ...
  • * CIL library *(* CIL module *) : error LNK2005: _DllMain@12 already defined in mfcs120u.lib(dllmodu
  • ../depcomp: line 571: exec: g++: not found