<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      C# 高性能獲取對象屬性

      目的:嘗試幾種不同的獲取對象屬性的方法,并對比他們的性能

      1. 獲取屬性的幾種方法

      1.1 準備

      定義一個Person類,實例化一個對象,測試獲取對象的屬性。

       public class Person
      {
          /// <summary>
          /// 姓名
          /// </summary>
          public string Name { get; set; }
      
          /// <summary>
          /// 英文名
          /// </summary>
          public string EnglishName { get; set; }
      
          /// <summary>
          /// 年齡
          /// </summary>
          public int Age { get; set; }
      
      }
      

      1.2 直接調用

      為了把if判斷,放到for 循環外面,代碼寫的有些啰嗦。因為在千萬級別的循環里面,if判斷也會相對比較耗時,影響對比結果。

      /// <summary>
      /// 屬性訪問性能測試。
      /// </summary>
      public static string YuanShengTest(Person person, string fieldName)
      {
          string result = "";
          Stopwatch stopwatch = new Stopwatch();
          stopwatch.Start();
          if (fieldName == nameof(person.Name))
          {
              for (int i = 0; i < Times; i++)
              {
                  string name = person.Name;
                  if (i == 0)
                  {
                      result = name;
                  }
              }
          }
          else if (fieldName == nameof(person.EnglishName))
          {
              for (int i = 0; i < Times; i++)
              {
                  string name = person.EnglishName;
                  if (i == 0)
                  {
                      result = name;
                  }
              }
          }
          else
          {
              for (int i = 0; i < Times; i++)
              {
                  int age = person.Age;
                  if (i == 0)
                  {
                      result = age.ToString();
                  }
              }
          }
          stopwatch.Stop();
          Console.WriteLine($"{result}==>普通屬性訪問耗時:{stopwatch.ElapsedMilliseconds}ms");
          return result;
      }
      

      1.3 反射

      動態獲取屬性,非常常用的方式,方便,代碼簡潔。但是每次獲取屬性,都調用PropertyInfo.GetValue() ,需要運行時進行完整的方法查找和參數驗證,在這里的幾個方法中,理論上是性能最差的。

      /// <summary>
      ///  反射性能測試
      /// </summary>
      public static string ReflectionTest(Person person, string fieldName)
      {
          string result = "";
          Stopwatch stopwatch = new Stopwatch();
          stopwatch.Start();
          var personType = typeof(Person); //person.GetType();
          var personName = personType.GetProperty(fieldName);
          for (int i = 0; i < Times; i++)
          {
              object? propertyValue = personName?.GetValue(person);
              if (i == 0)
              {
                  result = propertyValue.ToString();
              }
          }
          stopwatch.Stop();
          Console.WriteLine($"{result}==>反射屬性訪問耗時:{stopwatch.ElapsedMilliseconds}ms");
          return result;
      }
      

      1.4 動態構建Lambda

      動態構建Linq的Lambda表達式,然后編譯以后得到一個委托。首次運行成本高,需要編譯表達式。后續調用,編譯后的委托避免了,反射的運行時開銷,性能接近直接調用。
      生成的猥瑣類似下面:

      Func<Person, object> getName = p => p.Name;
      

      原理圖:

      具體實現:

       /// <summary>
       /// lambda表達式性能測試
       /// </summary>
       public static string LambdaTest(Person person, string fieldName)
       {
           string result = "";
           Stopwatch stopwatch = new Stopwatch();
           stopwatch.Start();
           Type type = typeof(Person);
           //構建表達式:Func<People, object> getName = p => p.Name;
           var parameter = Expression.Parameter(type, "p");//參數m
           PropertyInfo property = type.GetProperty(fieldName);  //要訪問的屬性名
           Expression expProperty = Expression.Property(parameter, property.Name);  //p.Name
           //變成表達式 m => m.Name
           var propertyDelegateExpression = Expression.Lambda<Func<Person, object>>(
               property.PropertyType.IsValueType ? Expression.Convert(expProperty, typeof(object)) : expProperty,  //訪問的屬性如果是值類型,需要顯式轉成object
               parameter);
           var propertyDelegate = (Func<Person, object>)propertyDelegateExpression.Compile();   //編譯為委托
      
           for (int i = 0; i < Times; i++)
           {
               object? propertyValue = propertyDelegate.Invoke(person);
               if (i == 0)
               {
                   result = propertyValue.ToString();
               }
           }
           stopwatch.Stop();
           Console.WriteLine($"{result}==>Lambda屬性訪問耗時:{stopwatch.ElapsedMilliseconds}ms");
           return result;
       }
      ```
      ### 1.5 Emit
      Emit 在運行時動態生成IL代碼方法,首次運行以后,后續會很快。跟表達式樹的方式,非常類似,都是生成委托方法,后續不需要運行時查找方法和參數檢查。但是少了額外包裝,更快。缺點也很明顯,寫起來比較復雜。
      原理圖:
      ![](https://img2024.cnblogs.com/blog/3590070/202506/3590070-20250602150329266-520941957.png)
      ```
      /// <summary>
      /// Emit 動態構建方法測試
      /// </summary>
      /// <param name="person"></param>
      /// <param name="fieldName"></param>
      /// <returns></returns>
      private static string EmitTest(Person person, string fieldName)
      {
          string result = "";
          Type type = typeof(Person);
          var property = type.GetProperty(fieldName);
          DynamicMethod method = new DynamicMethod("GetPropertyValue", typeof(object), new Type[] { type }, true);
          ILGenerator il = method.GetILGenerator();
          il.Emit(OpCodes.Ldarg_0);   //將索引0處的參數加載到求值堆棧上
          il.Emit(OpCodes.Callvirt, property.GetGetMethod());
      
          if (property.PropertyType.IsValueType)
          {
              il.Emit(OpCodes.Box, property.PropertyType);//值類型需要裝箱,因為返回類型是object
          }
          il.Emit(OpCodes.Ret);
          Func<Person, object> fun = method.CreateDelegate(typeof(Func<Person, object>)) as Func<Person, object>;
      
          Stopwatch stopwatch = Stopwatch.StartNew();
          for (int i = 0; i < Times; i++)
          {
              object propertyValue = fun.Invoke(person);
              if (i == 0)
              {
                  result = propertyValue.ToString();
              }
          }
          stopwatch.Stop();
          Console.WriteLine($"{result}==>Emit屬性訪問耗時:{stopwatch.ElapsedMilliseconds}ms");
          return result;
      }
      ```
      
      ## 2. 耗時對比
      用以下完整代碼,循環100000000 ,來一個耗時測試
      ```
      internal class Program
      {
          public const int Times = 100000000;
          static void Main(string[] args)
          {
              var person = new Person() { Name = "狗蛋", EnglishName = "GouDan", Age = 10 };
              string[] fieldNames = new string[] { nameof(Person.Name), nameof(Person.EnglishName), nameof(Person.Age) };
              foreach (var item in fieldNames)
              {
                  TestGetFieldValue(person, item);
              }
              //BenchmarkRunner.Run<PropertyAccessBenchmark>();
              Console.ReadLine();
          }
      
          /// <summary>
          ///  測試獲取屬性值性能
          /// </summary>
          /// <param name="person"></param>
          /// <returns></returns>
          private static void TestGetFieldValue(Person person, string fieldName)
          {
              Console.WriteLine($"開始測試{fieldName}屬性的獲取*************");
              YuanShengTest(person, fieldName);
              ReflectionTest(person, fieldName);
              LambdaTest(person, fieldName);
              EmitTest(person, fieldName);
              Console.WriteLine($"********************End*******************");
          }
      
          /// <summary>
          /// 屬性訪問性能測試。
          /// </summary>
          public static string YuanShengTest(Person person, string fieldName)
          {
              string result = "";
              Stopwatch stopwatch = Stopwatch.StartNew();
              if (fieldName == nameof(person.Name))
              {
                  for (int i = 0; i < Times; i++)
                  {
                      string name = person.Name;
                      if (i == 0)
                      {
                          result = name;
                      }
                  }
              }
              else if (fieldName == nameof(person.EnglishName))
              {
                  for (int i = 0; i < Times; i++)
                  {
                      string name = person.EnglishName;
                      if (i == 0)
                      {
                          result = name;
                      }
                  }
              }
              else
              {
                  for (int i = 0; i < Times; i++)
                  {
                      int age = person.Age;
                      if (i == 0)
                      {
                          result = age.ToString();
                      }
                  }
              }
              stopwatch.Stop();
              Console.WriteLine($"{result}==>普通屬性訪問耗時:{stopwatch.ElapsedMilliseconds}ms");
              return result;
          }
      
      
          /// <summary>
          ///  反射性能測試
          /// </summary>
          public static string ReflectionTest(Person person, string fieldName)
          {
              string result = "";
              var personType = typeof(Person); //person.GetType();
              var personName = personType.GetProperty(fieldName);
              Stopwatch stopwatch = Stopwatch.StartNew();
              for (int i = 0; i < Times; i++)
              {
                  object? propertyValue = personName?.GetValue(person);
                  if (i == 0)
                  {
                      result = propertyValue.ToString();
                  }
              }
              stopwatch.Stop();
              Console.WriteLine($"{result}==>反射屬性訪問耗時:{stopwatch.ElapsedMilliseconds}ms");
              return result;
          }
      
          /// <summary>
          /// lambda表達式性能測試
          /// </summary>
          public static string LambdaTest(Person person, string fieldName)
          {
              string result = "";
              Type type = typeof(Person);
              //構建表達式:Func<People, object> getName = p => p.Name;
              var parameter = Expression.Parameter(type, "p");//參數m
              PropertyInfo property = type.GetProperty(fieldName);  //要訪問的屬性名
              Expression expProperty = Expression.Property(parameter, property.Name);  //p.Name
              //變成表達式 m => m.Name
              var propertyDelegateExpression = Expression.Lambda<Func<Person, object>>(
                  property.PropertyType.IsValueType ? Expression.Convert(expProperty, typeof(object)) : expProperty,  //訪問的屬性如果是值類型,需要顯式轉成object
                  parameter);
              var propertyDelegate = (Func<Person, object>)propertyDelegateExpression.Compile();   //編譯為委托
      
              Stopwatch stopwatch = Stopwatch.StartNew();
              for (int i = 0; i < Times; i++)
              {
                  object? propertyValue = propertyDelegate.Invoke(person);
                  if (i == 0)
                  {
                      result = propertyValue.ToString();
                  }
              }
              stopwatch.Stop();
              Console.WriteLine($"{result}==>Lambda屬性訪問耗時:{stopwatch.ElapsedMilliseconds}ms");
              return result;
          }
      
      
          /// <summary>
          /// Emit 動態構建方法測試
          /// </summary>
          /// <param name="person"></param>
          /// <param name="fieldName"></param>
          /// <returns></returns>
          private static string EmitTest(Person person, string fieldName)
          {
              string result = "";
              Type type = typeof(Person);
              var property = type.GetProperty(fieldName);
              DynamicMethod method = new DynamicMethod("GetPropertyValue", typeof(object), new Type[] { type }, true);
              ILGenerator il = method.GetILGenerator();
              il.Emit(OpCodes.Ldarg_0);   //將索引0處的參數加載到求值堆棧上
              il.Emit(OpCodes.Callvirt, property.GetGetMethod());
      
              if (property.PropertyType.IsValueType)
              {
                  il.Emit(OpCodes.Box, property.PropertyType);//值類型需要裝箱,因為返回類型是object
              }
              il.Emit(OpCodes.Ret);
              Func<Person, object> fun = method.CreateDelegate(typeof(Func<Person, object>)) as Func<Person, object>;
      
              Stopwatch stopwatch = Stopwatch.StartNew();
              for (int i = 0; i < Times; i++)
              {
                  object propertyValue = fun.Invoke(person);
                  if (i == 0)
                  {
                      result = propertyValue.ToString();
                  }
              }
              stopwatch.Stop();
              Console.WriteLine($"{result}==>Emit屬性訪問耗時:{stopwatch.ElapsedMilliseconds}ms");
              return result;
          }
      }
      ```
      測試結果:
      ![](https://img2024.cnblogs.com/blog/3590070/202506/3590070-20250602150357329-2007154472.png)
      
      **獲取第一個屬性`Name`的時候,最快的居然不是直接獲取**,沒想明白。需要預熱?知道的大哥告訴一下。既然如此,再來一個基準測試看看結果。
      ## 3. 基準測試
      ### 3.1 安裝Nuget包
      ```
      NuGet\InstallPackage BenchmarkDotNet Version 0.15.0
      ```
      ### 3.2 編寫`PropertyAccessBenchmark`類
      ```
      using BenchmarkDotNet.Attributes;
      using fanshe.Model;
      using System.Linq.Expressions;
      using System.Reflection;
      using System.Reflection.Emit;
      
      public class PropertyAccessBenchmark
      {
          private Person person;
          private PropertyInfo property;
          private Func<Person, object> lambdaDelegate;
          private Func<Person, object> emitDelegate;
      
          [Params("Name", "EnglishName", "Age")]
          public string FieldName { get; set; }
      
          [GlobalSetup]
          public void Setup()
          {
              person = new Person { Name = "狗蛋", EnglishName = "GouDdan", Age = 10 };
              //反射
              var type = typeof(Person);
              property = type.GetProperty(FieldName);  //要訪問的屬性名
      
              //構建表達式:Func<People, object> getName = p => p.Name;
              //參數p
              var parameter = Expression.Parameter(type, "p");
              //要訪問的屬性p.Name
              Expression expProperty = Expression.Property(parameter, property.Name);
              //變成表達式 m => m.Name
              var propertyDelegateExpression = Expression.Lambda<Func<Person, object>>(
                  property.PropertyType.IsValueType ? Expression.Convert(expProperty, typeof(object)) : expProperty,  //訪問的屬性如果是值類型,需要顯式轉成object
                  parameter);
              lambdaDelegate = (Func<Person, object>)propertyDelegateExpression.Compile();   //編譯為委托       
      
              // Emit
              DynamicMethod method = new DynamicMethod("GetPropertyValue", typeof(object), new Type[] { type }, true);
              ILGenerator il = method.GetILGenerator();
              il.Emit(OpCodes.Ldarg_0);
              il.Emit(OpCodes.Callvirt, property.GetGetMethod());
              if (property.PropertyType.IsValueType)
              {
                  il.Emit(OpCodes.Box, property.PropertyType);
              }
              il.Emit(OpCodes.Ret);
              emitDelegate = (Func<Person, object>)method.CreateDelegate(typeof(Func<Person, object>));
          }
      
          [Benchmark]
          public object YuanSheng()
          {
              return person.EnglishName;
              //return FieldName switch
              //{
              //    "Name" => person.Name,
              //    "EnglishName" => person.EnglishName,
              //    "Age" => person.Age,
              //    _ => null
              //};
          }
      
          [Benchmark]
          public object Reflection()
          {
              return property.GetValue(person);
          }
      
          [Benchmark]
          public object Lambda()
          {
              return lambdaDelegate(person);
          }
      
          [Benchmark]
          public object Emit()
          {
              return emitDelegate(person);
          }
      }
      
      ```
      ### 3.3 調用`PropertyAccessBenchmark`
      ```
      BenchmarkRunner.Run<PropertyAccessBenchmark>();
      ```
      ### 3.3 Release生成,運行測試
      ![](https://img2024.cnblogs.com/blog/3590070/202506/3590070-20250602150419107-1115134864.png)
      
      結果:**直接訪問(YuanSheng) > 表達式樹(Lambda) ≈ Emit > 反射(Reflection)**
      Emit 略微慢于表達式樹(Lambda),這是沒想到的。應該是Emit代碼,什么地方沒有優化好。Emit 不怎么會,歡迎大佬指導!
      posted @ 2025-06-02 15:04  dotNet編程拾光  閱讀(50)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 中文字幕乱码中文乱码毛片| 最新中文字幕av无码专区不| 日韩亚洲视频一区二区三区| 国产欧美在线观看一区| 国产AV福利第一精品| 亚洲在av极品无码天堂| 日韩深夜免费在线观看| 国产精品久久久国产盗摄| 日韩高清在线亚洲专区不卡| 国产网友愉拍精品视频手机| 日韩精品无码人妻一区二区三区| 亚洲狼人久久伊人久久伊| 一区二区亚洲精品国产精| 内射干少妇亚洲69XXX| 亚洲精品天堂在线观看| 久久精品伊人狠狠大香网| 亚洲高清中文字幕在线看不卡| 久久国产免费观看精品3| 在线a人片免费观看| 性饥渴少妇AV无码毛片| 不卡一区二区国产在线| 国产欧美亚洲精品a第一页| 亚洲AV永久天堂在线观看| 国产精品午夜福利视频| 丰满岳乱妇久久久| 人成午夜免费大片| 日本欧美一区二区三区在线播放| 少妇真人直播免费视频| 免费看欧美日韩一区二区三区| 国产精品中文字幕av| 久久精品国产色蜜蜜麻豆| 免费人成网站免费看视频| 亚洲国产高清在线观看视频| 99久久无码一区人妻a黑| 日韩一区二区三区亚洲一| 国产精品亚洲综合久久小说| 亚洲国产精品久久久天堂麻豆宅男 | 国产精品一区在线蜜臀 | 国产一区日韩二区欧美三区| 午夜成人鲁丝片午夜精品| 色秀网在线观看视频免费|