.net core 高性能對象轉換

来源:https://www.cnblogs.com/castyuan/archive/2018/07/09/9285101.html
-Advertisement-
Play Games

關於對象轉換已經有不少輪子(AutoMapper,TinyMapper) .出於項目需要,手動造一個簡單輪子。先貼代碼 g>1.採用靜態泛型類緩存,避免了拆箱裝箱操作。 2.對於轉換對象中有,欄位名一樣但是類型不一樣的類時仍可以用 1 public static class Mapper<TSour ...


關於對象轉換已經有不少輪子(AutoMapper,TinyMapper) .出於項目需要,手動造一個簡單輪子。先貼代碼

g>1.採用靜態泛型類緩存,避免了拆箱裝箱操作。

2.對於轉換對象中有,欄位名一樣但是類型不一樣的類時仍可以用

  

 1     public static class Mapper<TSource, TTarget> where TSource : class where TTarget : class
 2     {
 3         public readonly static Func<TSource, TTarget> Map;
 4 
 5         static Mapper()
 6         {
 7             if (Map == null)
 8                 Map = GetMap();
 9         }
10 
11         private static Func<TSource, TTarget> GetMap()
12         {
13             var sourceType = typeof(TSource);
14             var targetType = typeof(TTarget);
15 
16             var parameterExpression = Expression.Parameter(sourceType, "p");
17             var memberInitExpression = GetExpression(parameterExpression, sourceType, targetType);
18 
19             var lambda = Expression.Lambda<Func<TSource, TTarget>>(memberInitExpression, parameterExpression);
20             return lambda.Compile();
21         }
22 
23         /// <summary>
24         /// 根據轉換源和目標獲取表達式樹
25         /// </summary>
26         /// <param name="parameterExpression">表達式參數p</param>
27         /// <param name="sourceType">轉換源類型</param>
28         /// <param name="targetType">轉換目標類型</param>
29         /// <returns></returns>
30         private static MemberInitExpression GetExpression(Expression parameterExpression, Type sourceType, Type targetType)
31         {
32             var memberBindings = new List<MemberBinding>();
33             foreach (var targetItem in targetType.GetProperties().Where(x => x.PropertyType.IsPublic && x.CanWrite))
34             {
35                 var sourceItem = sourceType.GetProperty(targetItem.Name);
36 
37                 //判斷實體的讀寫許可權
38                 if (sourceItem == null || !sourceItem.CanRead || sourceItem.PropertyType.IsNotPublic)
39                     continue;
40 
41                 //標註NotMapped特性的屬性忽略轉換
42                 if (sourceItem.GetCustomAttribute<NotMappedAttribute>() != null)
43                     continue;
44 
45                 var propertyExpression = Expression.Property(parameterExpression, sourceItem);
46 
47                 //判斷都是class 且類型不相同時
48                 if (targetItem.PropertyType.IsClass && sourceItem.PropertyType.IsClass && targetItem.PropertyType != sourceItem.PropertyType)
49                 {
50                     if (targetItem.PropertyType != targetType)//防止出現自己引用自己無限遞歸
51                     {
52                         var memberInit = GetExpression(propertyExpression, sourceItem.PropertyType, targetItem.PropertyType);
53                         memberBindings.Add(Expression.Bind(targetItem, memberInit));
54                         continue;
55                     }
56                 }
57 
58                 if (targetItem.PropertyType != sourceItem.PropertyType)
59                     continue;
60 
61                 memberBindings.Add(Expression.Bind(targetItem, propertyExpression));
62             }
63             return Expression.MemberInit(Expression.New(targetType), memberBindings);
64         }
65     }
View Code

 

3.調用方法如下

 (1)構造樣例類

    public class A
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public C User { get; set; }

        /// <summary>
        /// 標註為notmapped特性時,不轉換賦值
        /// </summary>
        [System.ComponentModel.DataAnnotations.Schema.NotMapped]
        public D UserA { get; set; }

    }

    public class B
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public D User { get; set; }
public D UserA { get; set; } } public class C { public int Id { get; set; } public string Name { get; set; } } public class D { public int Id { get; set; } public string Name { get; set; } }

  

  (2) 調用

            var a = new A
            {
                Id = 1,
                Name = "張三",
                User = new C
                {
                    Id = 1,
                    Name = "李四"
                }
            };
B b = Mapper<A, B>.Map(a);//得到轉換結果

  

4.性能測試

 1             var length = 10000000;
 2             var listA = new List<A>();
 3             for (int i = 0; i < length; i++)
 4             {
 5                 listA.Add(new A
 6                 {
 7                     Id = i,
 8                     Name = "張三",
 9                     User = new C
10                     {
11                         Id = i,
12                         Name = "李四"
13                     }
14                 });
15             }
16 
17             var sw = Stopwatch.StartNew();
18             for (int i = 0; i < length; i++)
19             {
20                 var item = listA[i];
21                 var b = new B
22                 {
23                     Id = item.Id,
24                     Name = item.Name,
25                     User = new D
26                     {
27                         Id = i,
28                         Name = "李四",
29                     }
30                 };
31             }
32             sw.Stop();
33             Console.WriteLine($"原生的時間:{sw.ElapsedMilliseconds}ms");
34 
35             //表達式
36             Mapper<A, B>.Map(listA[0]);//預先編譯緩存
37             sw.Restart();
38             for (int i = 0; i < length; i++)
39             {
40                 Mapper<A, B>.Map(listA[i]);
41             }
42             sw.Stop();
43             Console.WriteLine($"表達式的時間:{sw.ElapsedMilliseconds}ms");
44 
45             //AutoMapper
46             AutoMapper.Mapper.Initialize(cfg => cfg.CreateMap<A, B>());
47             sw.Restart();
48             for (int i = 0; i < length; i++)
49             {
50                 var b = AutoMapper.Mapper.Map<B>(listA[i]);
51             }
52             sw.Stop();
53             Console.WriteLine($"AutoMapper時間:{sw.ElapsedMilliseconds}ms");
54 
55             //TinyMapper
56             TinyMapper.Bind<A, B>();
57             sw.Restart();
58             for (int i = 0; i < length; i++)
59             {
60                 var b = TinyMapper.Map<B>(listA[i]);
61             }
62             sw.Stop();
63             Console.WriteLine($"TinyMapper時間:{sw.ElapsedMilliseconds}ms");
64 
65             Console.ReadLine();
View Code

 

 

5. 1000萬數據不帶子類集結果

 

6. 1000萬數據帶子類集結果 

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...