最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

詳解C#通過反射獲取對象的幾種方式比較

 更新時間:2022年06月14日 09:19:58   作者:HappyGirl快樂女孩  
本文主要介紹了C#通過反射獲取對象的幾種方式比較,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧

在本文中,對比了常見的幾種反射的方法,介紹了它們分別應該如何使用,每種的簡易度和靈活度,然后做了基準測試,一起看看這之間的性能差距。

按照使用的簡易度和靈活度,做了下邊的排序,可能還有一些其他的反射方式,比如 Source Generators,本文中只針對以下幾種進行測試。

  • 直接調(diào)用 ConstructorInfo 對象的Invoke()方法
  • 使用 Activator.CreateInstance()
  • 使用 Microsoft.Extensions.DependencyInjection
  • 黑科技 Natasha•使用表達式 Expression
  • 使用 Reflection.Emit 創(chuàng)建動態(tài)方法

使用標準反射的 Invoke 方法

Type typeToCreate = typeof(Employee);
ConstructorInfo ctor = typeToCreate.GetConstructor(System.Type.EmptyTypes);
Employee employee = ctor.Invoke(null) as Employee;

第一步是通過 typeof() 獲取對象的類型,你也可以通過 GetType 的方式,然后調(diào)用 GetConstructor 方法,傳入 System.Type.EmptyTypes 參數(shù),實際上它是一個空數(shù)組 (new Type[0]), 返回 ConstructorInfo對象, 然后調(diào)用 Invoke 方法,會返回一個 Employee 對象。

這是使用反射的最簡單和最靈活的方法之一,因為可以使用類似的方法來調(diào)用對象的方法、接口和屬性等,但是這個也是最慢的反射方法之一。

使用 Activator.CreateInstance

如果你需要創(chuàng)建對象的話,在.NET Framework 和 .NET Core 中正好有一個專門為此設計的靜態(tài)類,System.Activator, 使用方法非常的簡單,還可以使用泛型,而且你還可以傳入其他的參數(shù)。

Employee employee = Activator.CreateInstance<Employee>();

使用 Microsoft.Extensions.DependencyInjection

接下來就是在.NET Core 中很熟悉的 IOC 容器,Microsoft.Extensions.DependencyInjection,把類型注冊到容器中后,然后使用 IServiceProvider 來獲取對象,這里使用了 Transient 的生命周期,保證每次都會創(chuàng)建一個新的對象

IServiceCollection services = new ServiceCollection();
 
services.AddTransient<Employee>();
 
IServiceProvider provider = services.BuildServiceProvider();
 
Employee employee = provider.GetService<Employee>();

Natasha

Natasha 是基于 Roslyn 開發(fā)的動態(tài)程序集構(gòu)建庫,直觀和流暢的 Fluent API 設計,通過 roslyn 的強大賦能, 可以在程序運行時創(chuàng)建代碼,包括 程序集、類、結(jié)構(gòu)體、枚舉、接口、方法等, 用來增加新的功能和模塊,這里用 NInstance 來創(chuàng)建對象。

// Natasha 初始化
NatashaInitializer.Initialize();
 
Employee employee = Natasha.CSharp.NInstance.Creator<Employee>().Invoke();

使用表達式 Expression

表達式 Expression 其實也已經(jīng)存在很長時間了,在 System.Linq.Expressions 命名空間下, 并且是各種其他功能 (LINQ) 和庫(EF Core) 不可或缺的一部分,在許多方面,它類似于反射,因為它們允許在運行時操作代碼。

NewExpression constructorExpression = Expression.New(typeof(Employee));
Expression<Func<Employee>> lambdaExpression = Expression.Lambda<Func<Employee>>(constructorExpression);
Func<Employee> func = lambdaExpression.Compile();
Employee employee = func();

 表達式提供了一種用于聲明式代碼的高級語言,前兩行創(chuàng)建了的表達式, 等價于 () => new Employee(),然后調(diào)用 Compile 方法得到一個 Func<> 的委托,最后調(diào)用這個 Func 返回一個Employee對象

使用 Emit

Emit 主要在 System.Reflection.Emit 命名空間下,這些方法允許在程序中直接創(chuàng)建 IL (中間代碼) 代碼,IL 代碼是指編譯器在編譯程序時輸出的 "偽匯編代碼", 也就是編譯后的dll,當程序運行的時候,.NET CLR 中的 JIT編譯器 將這些 IL 指令轉(zhuǎn)換為真正的匯編代碼。

接下來,需要在運行時創(chuàng)建一個新的方法,很簡單,沒有參數(shù),只是創(chuàng)建一個Employee對象然后直接返回

Employee DynamicMethod()
{
    return new Employee();
}

這里主要使用到了 System.Reflection.Emit.DynamicMethod 動態(tài)創(chuàng)建方法 

 DynamicMethod dynamic = new("DynamicMethod", typeof(Employee), null, typeof(ReflectionBenchmarks).Module, false);

創(chuàng)建了一個 DynamicMethod 對象,然后指定了方法名,返回值,方法的參數(shù)和所在的模塊,最后一個參數(shù) false 表示不跳過 JIT 可見性檢查。

現(xiàn)在有了方法簽名,但是還沒有方法體,還需要填充方法體,這里需要C#代碼轉(zhuǎn)換成 IL代碼,實際上它是這樣的

IL_0000: newobj instance void Employee::.ctor()

IL_0005: ret

然后使用 ILGenerator 來操作IL代碼, 然后創(chuàng)建一個 Func<> 的委托, 最后執(zhí)行該委托返回一個 Employee 對象

ConstructorInfor ctor = typeToCreate.GetConstructor(System.Type.EmptyTypes);
 
ILGenerator il = createHeadersMethod.GetILGenerator();
il.Emit(OpCodes.Newobj, Ctor);
il.Emit(OpCodes.Ret);
 
Func<Employee> emitActivator = dynamic.CreateDelegate(typeof(Func<Employee>)) as Func<Employee>;
Employee employee = emitActivator();

對比測試

using BenchmarkDotNet.Attributes;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Linq.Expressions;
using System.Reflection;
using System.Reflection.Emit;
 
namespace ReflectionBenchConsoleApp
{
    public class Employee { }
 
    public class ReflectionBenchmarks
    { 
        private readonly ConstructorInfo _ctor;
        private readonly IServiceProvider _provider;
        private readonly Func<Employee> _expressionActivator;
        private readonly Func<Employee> _emitActivator;
        private readonly Func<Employee> _natashaActivator;
 
 
        public ReflectionBenchmarks()
        { 
            _ctor = typeof(Employee).GetConstructor(Type.EmptyTypes); 
 
            _provider = new ServiceCollection().AddTransient<Employee>().BuildServiceProvider(); 
 
            NatashaInitializer.Initialize();
            _natashaActivator = Natasha.CSharp.NInstance.Creator<Employee>();
 
 
            _expressionActivator = Expression.Lambda<Func<Employee>>(Expression.New(typeof(Employee))).Compile(); 
 
            DynamicMethod dynamic = new("DynamicMethod", typeof(Employee), null, typeof(ReflectionBenchmarks).Module, false);  
            ILGenerator il = dynamic.GetILGenerator();
            il.Emit(OpCodes.Newobj, typeof(Employee).GetConstructor(System.Type.EmptyTypes));
            il.Emit(OpCodes.Ret); 
            _emitActivator = dynamic.CreateDelegate(typeof(Func<Employee>)) as Func<Employee>;  
 
        }  
 
        [Benchmark(Baseline = true)]
        public Employee UseNew() => new Employee(); 
 
        [Benchmark]
        public Employee UseReflection() => _ctor.Invoke(null) as Employee;
 
        [Benchmark]
        public Employee UseActivator() => Activator.CreateInstance<Employee>();  
 
        [Benchmark]
        public Employee UseDependencyInjection() => _provider.GetRequiredService<Employee>();
 
 
        [Benchmark]
        public Employee UseNatasha() => _natashaActivator();
 
 
        [Benchmark]
        public Employee UseExpression() => _expressionActivator(); 
 
 
        [Benchmark]
        public Employee UseEmit() => _emitActivator(); 
 
 
    }  
}

接下來,還修改 Program.cs,注意這里需要在 Release 模式下運行測試

using BenchmarkDotNet.Running; 
 
namespace ReflectionBenchConsoleApp
{
    public class Program
    {
        public static void Main(string[] args)
        { 
            var sumary = BenchmarkRunner.Run<ReflectionBenchmarks>();
        }
    } 
 
}

測試結(jié)果

 環(huán)境是 .NET 6 preview5, 使用標準反射的 Invoke() 方法雖然簡單,但它是最慢的一種,使用 Activator.CreateInstance() 和 Microsoft.Extensions.DependencyInjection() 的時間差不多,時間是直接 new 創(chuàng)建的16倍,使用表達式 Expression 表現(xiàn)最優(yōu)秀,Natasha 真是黑科技,比用Emit 還快了一點,使用Emit 是直接 new 創(chuàng)建的時間的1.8倍。你應該發(fā)現(xiàn)了各種方式之間的差距,但是需要注意的是這里是 ns 納秒,一納秒是一秒的十億分之一。

總結(jié)

這里簡單對比了幾種創(chuàng)建對象的方法,測試的結(jié)果也可能不是特別準確,有興趣的還可以在 .net framework 上面進行測試,希望對您有用!

相關(guān)鏈接 

https://andrewlock.net/benchmarking-4-reflection-methods-for-calling-a-constructor-in-dotnet/

https://github.com/dotnetcore/Natasha

到此這篇關(guān)于詳解C#通過反射獲取對象的幾種方式比較的文章就介紹到這了,更多相關(guān)C# 反射獲取對象內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C#實現(xiàn)TCP和UDP通信的示例詳解

    C#實現(xiàn)TCP和UDP通信的示例詳解

    這篇文章主要為大家詳細介紹了C#實現(xiàn)TCP和UDP通信的相關(guān)知識,文中的示例代碼講解詳細,具有一定的學習價值,感興趣的小伙伴可以了解一下
    2023-03-03
  • string與stringbuilder兩者的區(qū)別

    string與stringbuilder兩者的區(qū)別

    今天小編就為大家分享一篇關(guān)于string與stringbuilder兩者的區(qū)別,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2019-01-01
  • C#實現(xiàn)矩陣轉(zhuǎn)置的方法

    C#實現(xiàn)矩陣轉(zhuǎn)置的方法

    這篇文章主要介紹了C#實現(xiàn)矩陣轉(zhuǎn)置的方法,實例分析了C#針對矩陣運算的相關(guān)技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-08-08
  • C#中IsNullOrEmpty和IsNullOrWhiteSpace的使用方法及區(qū)別解析

    C#中IsNullOrEmpty和IsNullOrWhiteSpace的使用方法及區(qū)別解析

    今天我們將探討C#中兩個常用的字符串處理方法:IsNullOrEmpty和IsNullOrWhiteSpace,本文中,我們將詳細解釋這兩個方法的功能和使用場景,并幫助您更好地理解它們之間的區(qū)別,本文結(jié)合實例代碼給大家介紹的非常詳細,需要的朋友參考下吧
    2023-07-07
  • C# 運算符 ?、??、?: 各種問號的用法和說明

    C# 運算符 ?、??、?: 各種問號的用法和說明

    本文介紹C#中三種常見的問號運算符的使用方法,簡單講解給大家,希望對大家有所幫助。
    2016-04-04
  • C#使用Thrift作為RPC框架入門詳細教程

    C#使用Thrift作為RPC框架入門詳細教程

    這篇文件我們講了從0到1使用thrift框架的方法,也講了一些該框架的基本知識,本文將詳細介紹 Thrift 在C#語言下的使用方式,并且提供豐富的實例代碼加以解釋說明,幫助使用者快速構(gòu)建服務,感興趣的朋友一起看看吧
    2021-11-11
  • C#給Word中的字符添加著重號的方法詳解

    C#給Word中的字符添加著重號的方法詳解

    這篇文章主要為大家詳細介紹了如何利用C#實現(xiàn)給Word中的字符添加著重號,文中的示例代碼講解詳細,對我們學習有一定幫助,需要的可以參考一下
    2022-05-05
  • 淺談C# StringBuilder內(nèi)存碎片對性能的影響

    淺談C# StringBuilder內(nèi)存碎片對性能的影響

    這篇文章主要介紹了淺談StringBuilder內(nèi)存碎片對性能的影響,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-03-03
  • C#實現(xiàn)自定義Dictionary類實例

    C#實現(xiàn)自定義Dictionary類實例

    這篇文章主要介紹了C#實現(xiàn)自定義Dictionary類,較為詳細的分析了Dictionary類的功能、定義及用法,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-08-08
  • C#訪問命令行的兩種方法

    C#訪問命令行的兩種方法

    這篇文章主要介紹了C#訪問命令行的兩種方法,實例分析了C#操作命令行的兩種常用技巧,需要的朋友可以參考下
    2015-06-06

最新評論

广饶县| 丘北县| 治多县| 沙坪坝区| 孙吴县| 清丰县| 西乡县| 岢岚县| 徐州市| 南靖县| 莱阳市| 北宁市| 兴和县| 伊吾县| 奇台县| 阳曲县| 北京市| 松潘县| 桐城市| 马边| 综艺| 彭山县| 肥东县| 桐梓县| 四平市| 佛冈县| 木兰县| 土默特右旗| 阿勒泰市| 合作市| 莱西市| 巴楚县| 夹江县| 广宗县| 平邑县| 金阳县| 凤城市| 通化市| 肇源县| 仙游县| 宝清县|