`
RednaxelaFX
  • 浏览: 3047682 次
  • 性别: Icon_minigender_1
  • 来自: 海外
社区版块
存档分类
最新评论

SRE里的Builder系列到Info系列的转换

    博客分类:
  • .NET
阅读更多
如果你试用(没错字,我就是说“试用”而不是“使用”)过System.Reflection.Emit的功能,可能会觉得这帖标题很怪——Builder系列跟对应的Info系列不是同根生么,前者继承对应的后者:
Builder系列(派生类) Info系列(基类)
System.Reflection.Emit.AssemblyBuilder System.Reflection.Assembly
System.Reflection.Emit.ModuleBuilder System.Reflection.Module
System.Reflection.Emit.TypeBuilder System.Type
System.Reflection.Emit.EnumBuilder System.Type
System.Reflection.Emit.GenericTypeParameterBuilder System.Type
System.Reflection.Emit.FieldBuilder System.Reflection.FieldInfo
System.Reflection.Emit.MethodBuilder System.Reflection.MethodInfo
System.Reflection.Emit.ConstructorBuilder System.Reflection.ConstructorInfo
System.Reflection.Emit.PropertyBuilder System.Reflection.PropertyInfo
System.Reflection.Emit.EventBuilder System.Object

(最后一个不是Info系列的,所以用灰色表示了。前面的Assembly、Module和Type都算在“广义的Info系列”里)

那么通过SRE创建出一个类型之后,手上的Builder系列类型可以直接用于反射吗?
答案是:不行,Builder系列唯一的使命就是Emit,没有别的用途。
看个例子就明白:demo.cs
using System;
using System.Reflection;
using System.Reflection.Emit;

static class Demo {
    static void Main(string[] args) {
        var assemblyName = new AssemblyName("DemoAssembly");
        var assemblyBuilder = AppDomain.CurrentDomain
            .DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
        var moduleBuilder = assemblyBuilder.DefineDynamicModule(
            "DemoAssembly" );
        var typeBuilder = moduleBuilder.DefineType(
            "TestType00", TypeAttributes.Public);
        var fieldBuilder = typeBuilder.DefineField(
            "x", typeof(int), FieldAttributes.Private);
        var testType = typeBuilder.CreateType();
        
        // get a FieldInfo through normal reflection
        var fieldInfo = testType.GetField(
            "x", BindingFlags.NonPublic | BindingFlags.Instance);

        // create new instance of TestType00
        var instance = Activator.CreateInstance(testType);
        // set the field x through normal reflection
        fieldInfo.SetValue(instance, 2);
        try {
            // try to get the field x through FieldBuilder
            // a FieldBuilder is a FieldInfo, but this won't work...
            Console.WriteLine(fieldBuilder.GetValue(instance));
        } catch (Exception e) {
            Console.WriteLine(e);
//System.NotSupportedException: The invoked member is not supported in a dynamic module.
//   at System.Reflection.Emit.FieldBuilder.GetValue(Object obj)
//   at Demo.Main(String[] args) in d:\demo.cs:line 29
        }
        
        // get a FieldInfo from a FieldBuilder
        var fieldInfoFromResolved = moduleBuilder.ResolveField(
                moduleBuilder.GetFieldToken(fieldBuilder).Token);
        // WARNING: can't call resolve before calling CreateType,
        // because resolving a type will load the type; an unfinished
        // type cannot be loaded
        Console.WriteLine(fieldInfo == fieldInfoFromResolved);       // true
        
        // get the field x through converted FieldInfo
        Console.WriteLine(fieldInfoFromResolved.GetValue(instance)); // 2
        
        // set the field x through converted FieldInfo
        fieldInfoFromResolved.SetValue(instance, 5);
        // get the field x through normal reflection
        Console.WriteLine(fieldInfo.GetValue(instance));             // 5
    }
}

稍微解释一下这段代码:
开头的部分都是很常见的SRE boilerplate,先得到AssemblyBuilder,然后ModuleBuilder,然后TypeBuilder。接下来定义了一个域,得到一个FieldBuilder。如开头所说,FieldBuilder继承FieldInfo,那么它似乎也应该可以用于反射?马上try一下,却得到NotSupportedException。此路不通。
接下来的部分就有趣了。FieldBuilder虽然不能用于反射,但它仍然持有正确的metadata token;而从metadata就可以找出“真正”的FieldInfo。代码中第38的调用完成了这个工作。可以看到,这个方法得到的FieldInfo与通过正常反射得到的FieldInfo是同一个对象,自然就可以用于反射了。

先前跟老赵在twitter上的对话:
@rednaxelafx 写道
@jeffz_cn TypeBuilder不能直接用于反射,FieldBuilder不能用于Get/SetValue,MethodBuilder不能直接用于Invoke……一切都是因为metadata token……

@jeffz_cn 写道
@rednaxelafx FieldBuilder可以用来Stfld的,我的Eazy里刚用过,呵呵。你可以去获取代码看看,https://eazy.svn.codeplex.com/svn 在TypeBuilderExtensions.cs的79行。

老赵误解了我想说的“不能用于反射”的意思。Builder系列类型当然可以用于在生成IL时使用,因为那就是它们的本职工作——Emit。生成的IL在执行的时候并不会使用Builder系列类型的实例通过反射去取值/设值/调用等,当然没问题。一旦想把Builder系列直接用于Emit之外的用途,就会遇到NotSupportedException。

上面提到的转换,再举几个例子:
var type =
    moduleBuilder.ResolveType(moduleBuilder.GetTypeToken(typeBuilder).Token);
var fieldInfo =
    moduleBuilder.ResolveField(moduleBuilder.GetFieldToken(fieldBuilder).Token);
var methodInfo =
    moduleBuilder.ResolveMethod(moduleBuilder.GetMethodToken(methodBuilder).Token);

Metadata是以module为单位组织的,token只在module内部有效。所以ResolveXXX系列的方法也都是在ModuleBuilder上。

这种通过token去获取用于反射的Info系列类型的方法,比通过正常的反射API更高效易用。所以如果是刚动态创建出类型,手上还有Builder系列类型的实例的引用,就不必绕圈通过正常反射获取Info系列类型的实例了。
分享到:
评论

相关推荐

    20200719googleSRE.zip

    《Google SRE:运维解密》是一份深入探讨Google Site Reliability Engineering(SRE)实践的教程,旨在为那些有志于投身SRE领域的人提供宝贵的洞见。SRE是Google提出的一种工程方法论,它将传统的系统运维与软件工程...

    SRE Google运维解密

    SRE Google运维解密-中文版 SRE Google运维解密-中文版

    从ITIL到SRE-唯品会运维自动化实践.docx

    从 ITIL 到 SRE - 唯品会运维自动化实践 本文主要介绍了唯品会从 ITIL 到 SRE 的运维自动化实践经验,涵盖了 ITIL 的建设方法、瓶颈、困境、自动化和 SRE 尝试等方面。 一、ITIL 的建设方法及瓶颈 唯品会整个...

    eBPF与SRE工作的结合利用

    从SRE的角度来分析eBPF,能给其工作带来一系列的Tracing以及可观测方面的性能提升

    SRE Google运维解密.zip

    为了让亿万用户使用到稳定可靠的服务,Google 组建了一支专业的团队负责运行这些后端服务,这些工程师有一个共同的名字:Site Reliability Engineer。了解 Google SRE 的人常说的一句话是:和你们相比,大部分公司还...

    SRE系统辅助工具 好帮手

    在IT行业中,SRE(Site Reliability Engineering,网站可靠性工程)是一种综合了软件工程与系统运维的实践,致力于提供高可用、高性能、可扩展的在线服务。在这个领域,"SRE系统辅助工具 好帮手"可能是指一种用于...

    Catchpoint-SRE-Report-2020 (中文发布版).pdf

    今年我们花了一点额外的时间进行研究,因为新冠肺炎的大流行给SRE角色的工作增加了一层复杂性。今年的报告从一个独特的角度展示了IT服务工作如何适应远程IT时代。 下载《2020年SRE报告》,了解在向远程IT转变的过程...

    google sre

    google sre 运维解密,为了积分不容易,希望大家支持~~~

    SRE_NFINDR_FCLS_高光谱_

    标题"SRE_NFINDR_FCLS_高光谱_"指的是一个与高光谱数据分析相关的项目,其中包含了三个主要的算法工具:SRE(Spectral Resolution Estimation,光谱分辨率估计)、NFINDR(Number of Findable Components in a ...

    SRE++Google运维解密

    SRE++Google运维解密

    专题资料(2021-2022年)SRE系列产品规格书.doc

    总结,SRE系列太阳能充放电控制器是用于太阳能系统的智能设备,它不仅实现了高效、安全的电力转换,还能根据环境条件自动调整工作模式,从而最大化利用太阳能资源,保护蓄电池,提高系统的整体性能和寿命。

    Cisco SRE 模块配置安装向导

    如果Cisco SRE未在出厂时预先安装,则需手动安装到Cisco 2900系列或Cisco 3900系列ISG2路由器中。具体步骤包括: 1. **物理安装**:根据“Cisco Internal Service Module - Services Ready Engine 安装指南”中的...

    更新SRE到968

    更新SRE到968 其他基本上不变

    SRE Google 无水印.扫描版

    SRE工作涉及到多个关键领域,包括监控、自动化、容量规划、故障恢复、事件管理以及服务级别目标(Service Level Objectives,SLOs)。以下是这些领域的详细解释: 1. **监控**:SREs利用各种工具和技术对系统的运行...

    SRE2.5

    在IT行业中,SRE(Site Reliability Engineering,网站可靠性工程)是一种将软件工程方法应用于运维领域的实践,旨在确保系统的高可用性、可扩展性和安全性。SRE2.5可能指的是某个SRE工具或实践的2.5版本,它专注于...

    SRE技能路线图.zip

    SRE也被称为站点可靠性工程师,就是通过在运营中使用软件开发的背景来处理基础结构问题。 企业需要可靠的系统来竞争和做出准确的决策。

    一个Qt开发的开源远程控制软件(SRE),还在开发中.zip

    【Qt开发的开源远程控制软件(SRE)】 Qt是一个跨平台的应用程序开发框架,它由The Qt Company提供,并在GNU Lesser General Public License (LGPL)和商业许可证下发布。Qt使得开发者能够用C++语言编写一次代码,...

    Google SRE 技术

    这涉及到对历史数据的分析、业务趋势的理解以及对技术趋势的洞察。 9. **变更管理**:SREs负责变更过程的管理和风险评估,确保每次变更都经过充分的测试和验证,降低引入新问题的风险。 10. **文化与价值观**:SRE...

Global site tag (gtag.js) - Google Analytics