<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          探究 C# dynamic動態(tài)類型本質(zhì)

          共 4688字,需瀏覽 10分鐘

           ·

          2023-08-17 02:49


          前言

          在做接口動態(tài)傳參的時候思考了個問題:如何把一個json字符串,轉(zhuǎn)成C#動態(tài)類?

          比如由

          {
              'userId': 100,
              'id': 1,
              'title''hello world',
              'completed'false
          }

          生成

          dynamic obj = new
          {
              userId = 100,
              id = 1,
              title = "hello world",
              completed = false,
          };

          解決這個問題前,我們先來了解一下dynamic動態(tài)類型。

          動態(tài)類型是什么?

          首先動態(tài)類型是靜態(tài)類,不是一種稱之為“動態(tài)”的類型,只不過這個類型的對象會跳過靜態(tài)類型檢查。

          也就是在編譯過程中不報錯,但是運行程序?qū)ο蟪跏蓟螅撌鞘裁搭愋停敲催€是什么類型。

          看個例子,有兩個動態(tài)類型obj1obj2

          dynamic obj1 = new
          {
          userId = 100,
          id = 1,
          title = "hello world",
          completed = false,
          };

          dynamic obj2 = new System.Dynamic.ExpandoObject();
          result.userId = 100;
          result.id = 1;
          result.title = "hello world";
          result.completed = false;

          Console.WriteLine("---obj1---");
          Console.WriteLine(obj1.userId);
          Console.WriteLine(obj1.id);
          Console.WriteLine(obj1.title);
          Console.WriteLine(obj1.completed);

          Console.WriteLine("\n---obj2---");
          Console.WriteLine(obj2.userId);
          Console.WriteLine(obj2.id);
          Console.WriteLine(obj2.title);
          Console.WriteLine(obj2.completed);

          運行結(jié)果如下

          他們輸出的結(jié)果一樣,但你認為他們的返回結(jié)果是一樣的嗎?

          obj1是一個類型為AnonymousType<int,int,string,bool>的匿名類,我們可以很輕松地通過反射的方式遍歷其成員變量:

          Type t = obj1.GetType();
          PropertyInfo[] pi = t.GetProperties();
          foreach (PropertyInfo p in pi)
          {

              var key = p.Name;
              var value = p.GetValue(obj1, null);
              Console.WriteLine(key + ": " + value);

          }

          打印如下:

          userId: 100
          id: 1
          title: hello world
          completed: False

          obj2則是System.Dynamic.ExpandoObject類型的對象,而且從初始化到對象生命周期結(jié)束。始終是這個類型。

          我們對obj2運行同樣的代碼,發(fā)現(xiàn)會報錯

          Type t = obj2.GetType();
          PropertyInfo[] pi = t.GetProperties();
          foreach (PropertyInfo p in pi)
          {

              var key = p.Name;
              var value = p.GetValue(obj1, null);
              Console.WriteLine(key + ": " + value);

          }

          報錯的原因是obj2并不包含真正的userId成員變量,因為其本質(zhì)是個ExpandoObject對象,

          可見dynamic關(guān)鍵字并不會改變C#變量在運行時的類型,它僅僅是在編譯階段跳過了靜態(tài)類型檢查。

          動態(tài)類型的特點是什么?

          然而你是可以通過重新賦值改變類型的,當然這是公共語言運行時 (CLR) 提供的動態(tài)技術(shù)。

          dynamic number = 1;
          Console.WriteLine(number.GetType());  //輸出System.Int

          number = "text";
          Console.WriteLine(number.GetType());  //輸出System.String

          當我用ILspy反編譯工具查看IL源碼的時候,竟發(fā)現(xiàn)number變量的類型是object,也就是整個過程經(jīng)過了裝箱拆箱,經(jīng)過了從內(nèi)存棧創(chuàng)建地址引用到堆中區(qū)域的改變。dynamic幫我們完成了這些動作。

          所以本質(zhì)上內(nèi)存中同一個對象不會平白無故從int類型轉(zhuǎn)換為string。畢竟C#不能像其他弱類型語言那樣使用。

          obj1匿名類的成員變量是只讀的。給它賦一個其他類型的值,將會報錯;而給obj2的成員變量賦其他類型的值,則不會報錯。

          obj1.userId = "100"; //運行時報錯
          obj2.userId = "100";

          在來看obj2,因為System.Dynamic.ExpandoObject 類型因?qū)崿F(xiàn)了 IDynamicMetaObjectProvider 因此它能通過.成員變量的方式訪問內(nèi)容。

          又因為System.Dynamic.ExpandoObject實現(xiàn)了IDictionary<string, object?>因此可以通過向字典添加KeyValue對象的形式向ExpandoObject對象添加成員變量,用[key]方式訪問內(nèi)容。代碼如下

          foreach (var entry in obj1)
          {
              (obj2 as IDictionary<stringobject>).Add(entry.Key, entry.Value.ToString());
          }

          通過.成員變量的方式訪問內(nèi)容,可以說這是偽裝的成員變量。但稍微一測試,就露餡了。

          動態(tài)類型如何用?

          現(xiàn)在我們來回答“如何把一個json字符串,轉(zhuǎn)成C#動態(tài)類”這個問題,答案是做不到

          首先用Newtonsoft.Json庫轉(zhuǎn)換的結(jié)果,無論是用JObject.Parse(json)還是JsonConvert.DeserializeObject(json)最后返回的結(jié)果是JToken類型的對象, 通過反編譯Newtonsoft.Json.dll,查看JToken類型,可見它還是一個繼承了IDictionary<string, object?>IDynamicMetaObjectProvider的類型,

          string json = @"{
              'userId': 100,
              'id': 1,
              'title': 'hello world',
              'completed': false
          }"
          ;
          var obj1 = JObject.Parse(json);

          dynamic obj2 = new System.Dynamic.ExpandoObject();

          foreach (var entry in obj1)
          {
              (obj2 as IDictionary<stringobject>).Add(entry.Key, entry.Value.ToString());
          }

          運行如上同樣的代碼檢查obj2

          Type t = obj2.GetType();
          PropertyInfo[] pi = t.GetProperties();
          foreach (PropertyInfo p in pi)
          {

              var key = p.Name;
              var value = p.GetValue(obj1, null);
              Console.WriteLine(key + ": " + value);

          }

          可以通過這樣向obj2動態(tài)添加成員變量,但是始終是字典方式提供的偽對象。

          轉(zhuǎn)自:林曉lx

          鏈接:cnblogs.com/jevonsflash/p/17232450.html

          瀏覽 193
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  一区A片 淫色一级 | 麻豆传剧原创在线观看 | 日本高清AⅤ在线播放 | 91丨人妻丨国产 | 亚洲人在线 |