日韩欧美人妻无码精品白浆,www.大香蕉久久网,狠狠的日狠狠的操,日本好好热在线观看

LOGO OA教程 ERP教程 模切知識(shí)交流 PMS教程 CRM教程 開(kāi)發(fā)文檔 其他文檔  
 
網(wǎng)站管理員

.NET Core 反射底層原理淺談

freeflydom
2024年11月16日 8:18 本文熱度 1842

前期綁定與后期綁定

在.NET中,前期綁定(Early Binding)是指在編譯時(shí)就確定了對(duì)象的類(lèi)型和方法,而后期綁定(Late Binding)或動(dòng)態(tài)綁定是在運(yùn)行時(shí)確定對(duì)象的類(lèi)型和方法。

前置知識(shí):C#類(lèi)型系統(tǒng)結(jié)構(gòu)

C#作為C++++ ,在類(lèi)型系統(tǒng)上沿用C++的類(lèi)型系統(tǒng)

前期綁定

在代碼能執(zhí)行之前,將代碼中依賴(lài)的assembly,module,class,method,field等類(lèi)型系統(tǒng)的元素提前構(gòu)建好。
前期綁定的優(yōu)點(diǎn)是編譯時(shí)類(lèi)型檢查,提高了類(lèi)型安全性和性能。缺點(diǎn)是如果需要更換類(lèi)型,需要重新編譯代碼。靈活性不夠

比如一個(gè)簡(jiǎn)單的的控制臺(tái),就自動(dòng)提前加載了各種需要的DLL文件。完成前期綁定。

后期綁定

后期綁定的優(yōu)點(diǎn)是可以在運(yùn)行時(shí)更改類(lèi)型,無(wú)需重新編譯代碼。缺點(diǎn)是在編譯時(shí)不進(jìn)行類(lèi)型檢查,可能導(dǎo)致運(yùn)行時(shí)錯(cuò)誤。
幾個(gè)常用的場(chǎng)景,比如dynamic ,多態(tài),System.Reflection

舉個(gè)例子,使用Reflection下的“元數(shù)據(jù)查詢(xún)API”,動(dòng)態(tài)加載DLL

            var dllpath = "xxx.dll";
            Assembly assembly = Assembly.LoadFrom(dllpath);//構(gòu)建Assembly+Module
            Type dataAccessType = assembly.GetType("xxxxx");//構(gòu)建Class(MethodTable+EEClass)
            object dataAccess = Activator.CreateInstance(dataAccessType);//在托管堆中創(chuàng)建MT實(shí)例
            MethodInfo addMethod = dataAccessType.GetMethod("Add");//構(gòu)建MethodDesc
			
            addMethod.Invoke(dataAccess, new object[] { "hello world" });//調(diào)用方法

反射

反射的本質(zhì)就是“操作元數(shù)據(jù)”

什么是元數(shù)據(jù)?

MetaData,本是上就是存儲(chǔ)在dll中的一個(gè)信息數(shù)據(jù)庫(kù),記錄了這個(gè)assembled中有哪些方法,哪些類(lèi),哪些屬性等等信息

可以看到,各種Table組成的信息,是不是類(lèi)似一個(gè)數(shù)據(jù)庫(kù)?

舉個(gè)例子:
執(zhí)行Type.GetType("int"),反射會(huì)在MetaData尋找"int"的類(lèi)型。但在運(yùn)行時(shí)會(huì)返回null.因?yàn)镸etaData中只有"System.Int32"這個(gè)字符串。

反射如何查詢(xún)MetaData?

通過(guò)Reflection XXXInfo系列API 查詢(xún)所有細(xì)節(jié)

Type t = typeof(System.IO.FileStream);
FieldInfo[] fi = t.GetFields(BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);
PropertyInfo[] pi = t.GetProperties(BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);
EventInfo[] ei = t.GetEvents(BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);
......

反射如何構(gòu)建類(lèi)型系統(tǒng)

通過(guò)Reflection XXXBuilder系列API 構(gòu)建一個(gè)全新的類(lèi)型

            AssemblyBuilder ab = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName("MyAssembly"), AssemblyBuilderAccess.RunAndCollect);//創(chuàng)建Assembly
            ModuleBuilder mob = ab.DefineDynamicModule("MyModule");//創(chuàng)建Module
            TypeBuilder tb = mob.DefineType("MyType", TypeAttributes.Public | TypeAttributes.Class);//創(chuàng)建Class
            MethodBuilder mb = tb.DefineMethod("SumMethod", MethodAttributes.Public | MethodAttributes.Static, typeof(int), new Type[] { typeof(int), typeof(int) });//創(chuàng)建MethodTable
            ILGenerator il = mb.GetILGenerator();//通過(guò)IL API 動(dòng)態(tài)構(gòu)建MethodDesc
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Ldarg_1);
            il.Emit(OpCodes.Add);
            il.Emit(OpCodes.Ret);
            Type type = tb.CreateType();  //mt + eeclass
            MethodInfo method = type.GetMethod("SumMethod");
            Console.WriteLine(method.Invoke(null, new object[] { 5, 10 }));

反射底層調(diào)用

C#的類(lèi)型系統(tǒng),與C++的類(lèi)型系統(tǒng)是一一對(duì)應(yīng)的。因此其底層必定是調(diào)用C++的方法。
示意圖如下,有興趣的小伙伴可以去參考coreclr的源碼

眼見(jiàn)為實(shí),以Invoke為例

反射到底慢在哪?

  1. 動(dòng)態(tài)解析
    從上面可知道,反射作為后期綁定,在runtime中要根據(jù)metadata查詢(xún)出信息,嚴(yán)重依賴(lài)字符串匹配,這本身就增加了額外的操作
  2. 動(dòng)態(tài)調(diào)用
    使用反射調(diào)用方法時(shí),先要將參數(shù)打包成數(shù)組,再解包到線程棧上。又是額外操作。
  3. 無(wú)法在編譯時(shí)優(yōu)化
    反射是動(dòng)態(tài)的臨時(shí)調(diào)用,JIT無(wú)法優(yōu)化。只能根據(jù)代碼一步一步執(zhí)行。
  4. 額外的安全檢查
    反射會(huì)涉及到訪問(wèn)和修改只讀字段等操作,運(yùn)行時(shí)需要進(jìn)行額外的安全性檢查,這也會(huì)增加一定的開(kāi)銷(xiāo)
  5. 緩存易失效
    反射如果參數(shù)發(fā)生變化,那么緩存的匯編就會(huì)失效。又需要重新查找與解析。

總之,千言萬(wàn)語(yǔ)匯成一句話(huà)。最好的反射就是不要用反射。除非你能保證對(duì)性能要求不高/緩存高命中率

CLR的對(duì)反射的優(yōu)化

除了緩存反射的匯編,.NET 中提供了一系列新特性來(lái)盡可能的繞開(kāi)“反射”

Emit

Emit 是 .NET 提供的一種動(dòng)態(tài)生成和編譯代碼的技術(shù)。通過(guò) Emit,我們可以動(dòng)態(tài)生成一個(gè)新的方法,這個(gè)方法可以直接訪問(wèn)私有成員,這對(duì)于一些特殊場(chǎng)景非常有用,比如動(dòng)態(tài)代理、代碼生成器、AOP(面向切面編程)等.

public class Person
{
    private int _age;
    public override string ToString()
    {
        return _age.ToString();
    }
}
static void EmitTest(Person person)
{
    // 獲取Person類(lèi)的類(lèi)型對(duì)象
    Type personType = typeof(Person);
    // 獲取私有字段_age的FieldInfo,無(wú)法避免部分使用反射
    FieldInfo ageField = personType.GetField("_age", BindingFlags.Instance | BindingFlags.NonPublic);
    if (ageField == null)
    {
        throw new ArgumentException("未找到指定的私有字段");
    }
    // 創(chuàng)建一個(gè)動(dòng)態(tài)方法
    DynamicMethod dynamicMethod = new DynamicMethod("SetAgeValue", null, new Type[] { typeof(Person), typeof(int) }, personType);
    // 獲取IL生成器
    ILGenerator ilGenerator = dynamicMethod.GetILGenerator();
    // 將傳入的Person對(duì)象加載到計(jì)算棧上(this指針)
    ilGenerator.Emit(OpCodes.Ldarg_0);
    // 將傳入的新值加載到計(jì)算棧上
    ilGenerator.Emit(OpCodes.Ldarg_1);
    // 將新值存儲(chǔ)到對(duì)應(yīng)的私有字段中
    ilGenerator.Emit(OpCodes.Stfld, ageField);
    // 返回(因?yàn)榉椒o(wú)返回值,這里只是結(jié)束方法執(zhí)行)
    ilGenerator.Emit(OpCodes.Ret);
    // 創(chuàng)建委托類(lèi)型,其簽名與動(dòng)態(tài)方法匹配
    Action<Person, int> setAgeAction = (Action<Person, int>)dynamicMethod.CreateDelegate(typeof(Action<Person, int>));
    // 通過(guò)委托調(diào)用動(dòng)態(tài)生成的方法來(lái)修改私有字段的值
    setAgeAction(person, 100);
}

切構(gòu)建代碼又臭又長(zhǎng)。

Expression

Expression 是 .NET 提供的一種表達(dá)式樹(shù)的技術(shù)。通過(guò) Expression,我們可以創(chuàng)建一個(gè)表達(dá)式樹(shù),然后編譯這個(gè)表達(dá)式樹(shù),生成一個(gè)可以訪問(wèn)私有成員的方法

static void ExpressionTest(Person person)
{
    // 獲取Person類(lèi)的類(lèi)型對(duì)象
    Type personType = typeof(Person);
    // 獲取私有字段_age的FieldInfo,無(wú)法避免部分使用反射
    FieldInfo ageField = personType.GetField("_age", BindingFlags.Instance | BindingFlags.NonPublic);
    if (ageField == null)
    {
        throw new ArgumentException("未找到指定的私有字段");
    }
    // 創(chuàng)建參數(shù)表達(dá)式,對(duì)應(yīng)傳入的Person對(duì)象實(shí)例
    ParameterExpression instanceParam = Expression.Parameter(personType, "instance");
    // 創(chuàng)建參數(shù)表達(dá)式,對(duì)應(yīng)傳入的新值
    ParameterExpression newValueParam = Expression.Parameter(typeof(int), "newValue");
    // 創(chuàng)建一個(gè)賦值表達(dá)式,將新值賦給私有字段
    BinaryExpression assignExpression = Expression.Assign(Expression.Field(instanceParam, ageField), newValueParam);
    // 創(chuàng)建一個(gè)包含賦值表達(dá)式的表達(dá)式塊,這里因?yàn)橹挥幸粋€(gè)賦值操作,所以塊里就這一個(gè)表達(dá)式
    BlockExpression blockExpression = Expression.Block(assignExpression);
    // 創(chuàng)建一個(gè)可執(zhí)行的委托,其類(lèi)型與表達(dá)式塊的邏輯匹配
    Action<Person, int> setAgeAction = Expression.Lambda<Action<Person, int>>(blockExpression, instanceParam, newValueParam).Compile();
    // 通過(guò)委托調(diào)用表達(dá)式樹(shù)生成的邏輯來(lái)修改私有字段的值
    setAgeAction(person, 100);
}

切構(gòu)建代碼又臭又長(zhǎng)。

UnsafeAccessorAttribute

.Net 8中引入了新特性UnsafeAccessorAttribute 。
使用該特性,來(lái)提供對(duì)私有字段的快速修改

static void New()
{
    var person = new Person();
    GetAgeField(person) = 100;
}
[UnsafeAccessor(UnsafeAccessorKind.Field, Name = "_age")]
static extern ref int GetAgeField(Person counter);

為什么它這么快?

對(duì)于C#來(lái)說(shuō),私有類(lèi)型是OOP語(yǔ)言的定義。它定義了什么是私有類(lèi)型,它的行為是什么。
但對(duì)于程序本身來(lái)說(shuō),代碼和數(shù)據(jù)都只是一段內(nèi)存,實(shí)際上你的指針想訪問(wèn)哪就訪問(wèn)哪。哪管你什么私有類(lèi)型。換一個(gè)指向地址不就得了。因此CLR開(kāi)放了這么一個(gè)口子,利用外部訪問(wèn)直接操作內(nèi)存??此拿?span style="color: rgb(255, 0, 0);">UnsafeAccessor就能猜到意圖了

3,2,1. 上匯編?。。?br>
直接將rax寄存器偏移量+8,直接返回int(占用4字節(jié),偏移量8)類(lèi)型的_age。 沒(méi)有Emit,Expression的彎彎繞繞,絲毫不拖泥帶水。

.NET 9中的改進(jìn)

支持泛型,更優(yōu)雅。
https://learn.microsoft.com/zh-cn/dotnet/core/compatibility/core-libraries/9.0/unsafeaccessor-generics

參考資料

https://blog.csdn.net/sD7O95O/article/details/133002995
https://learn.microsoft.com/zh-cn/dotnet/api/system.runtime.compilerservices.unsafeaccessorattribute?view=net-8.0

轉(zhuǎn)自https://www.cnblogs.com/lmy5215006/p/18545334


該文章在 2024/11/16 8:18:06 編輯過(guò)
關(guān)鍵字查詢(xún)
相關(guān)文章
正在查詢(xún)...
點(diǎn)晴ERP是一款針對(duì)中小制造業(yè)的專(zhuān)業(yè)生產(chǎn)管理軟件系統(tǒng),系統(tǒng)成熟度和易用性得到了國(guó)內(nèi)大量中小企業(yè)的青睞。
點(diǎn)晴PMS碼頭管理系統(tǒng)主要針對(duì)港口碼頭集裝箱與散貨日常運(yùn)作、調(diào)度、堆場(chǎng)、車(chē)隊(duì)、財(cái)務(wù)費(fèi)用、相關(guān)報(bào)表等業(yè)務(wù)管理,結(jié)合碼頭的業(yè)務(wù)特點(diǎn),圍繞調(diào)度、堆場(chǎng)作業(yè)而開(kāi)發(fā)的。集技術(shù)的先進(jìn)性、管理的有效性于一體,是物流碼頭及其他港口類(lèi)企業(yè)的高效ERP管理信息系統(tǒng)。
點(diǎn)晴WMS倉(cāng)儲(chǔ)管理系統(tǒng)提供了貨物產(chǎn)品管理,銷(xiāo)售管理,采購(gòu)管理,倉(cāng)儲(chǔ)管理,倉(cāng)庫(kù)管理,保質(zhì)期管理,貨位管理,庫(kù)位管理,生產(chǎn)管理,WMS管理系統(tǒng),標(biāo)簽打印,條形碼,二維碼管理,批號(hào)管理軟件。
點(diǎn)晴免費(fèi)OA是一款軟件和通用服務(wù)都免費(fèi),不限功能、不限時(shí)間、不限用戶(hù)的免費(fèi)OA協(xié)同辦公管理系統(tǒng)。
Copyright 2010-2025 ClickSun All Rights Reserved

久久国产乱子伦精品免费在线| 免费啪啪啪一区二区v| 猛插后入日韩少妇| 久久不卡高清无码| 人人妻人人澡人人爽欧美一区一亚| 久久日韩人妻在线| 国产69久久成人看精品| 囯产精品久久久久久久久久98| 我要看91视频黄色的| 午夜精品粉嫩高清二区| k8在线播放经典丰乳镇娇妻| 韩日激情在线| 亚洲人在成免费视频| 欧 美 亚 洲 一区二区片| 久久人妻性爱电影| 一二三区黄片| 久久久一二三四五区高清| 高黄np日本3D熟女| 偷拍精品视频99| 开心色婷五月天| 91伊人电影| 精品综合丝袜不卡| 性亚洲天堂| 亚洲欧洲日本国产综合在线| 日韩成人精品免费视频一区二区三区| 日韩操b的网站| 2017天天日天天射| 三级久久亚洲午夜| 熟女人妻第三页第四页第五页| 欧美日韩成人综合网| 久久午夜精品一区二区三区| 国产美女精品久久久久| 一级片欧美韩| 人人操人人在线| 九七超碰总院| 嗯啊嗯操我好爽视频| 欧洲亚洲囯产综合| 88精品人妻一区| 老湿机国产在线看片| tiktok成人在线观看一区| 一区二区综合欧美日本中文|