C# 通過Dynamic訪問System.Text.Json對象


目的


有時候在處理Http請求的時候偷懶不想定義一個Model來處理,使用Dynamic來直接操作請求的數據是非常方便的

C#中dynamic關鍵字


dynamic關鍵字和動態語言運行時(DLR)是.Net 4.0中新增的功能。

  • 什么是"動態"

    1. 編程語言有時可以划分為靜態類型化語言和動態類型化語言。C#和Java經常被認為是靜態化類型的語言,而Python、Ruby和JavaScript是動態類型語言。
    2. 一般而言,動態語言在編譯時不會對類型進行檢查,而是在運行時識別對象的類型。這種方法有利有弊:代碼編寫起來更快、更容易,但無法獲取編譯器錯誤,只能通過單元測試和其他方法來確保應用正常運行。
    3. C#最初是作為純靜態語言創建的,但是C#4添加了一些動態元素,用於改進與動態語言和框架之間的互操作性。C# 團隊考慮了多種設計選項,但最終確定添加一個新關鍵字來支持這些功能:dynamic。
    4. dynamic關鍵字可充當C#類型系統中的靜態類型聲明。這樣,C#就獲得了動態功能,同時仍然作為靜態類型化語言而存在。由於編譯時不會去檢查類型,所以導致IDE的IntellSense失效, 這點是dynamic的不便之處
  • dynamic、object還是var?

    那么,dynamic、Object和var之間的實際區別是什么?何時使用它們?

    1. 先說說var,經常有人會拿dynamic和var進行比較。實際上,var和dynamic完全是兩個概念,根本不應該放在一起做比較。
    2. var實際上編譯器拋給我們的語法糖,一旦被編譯,編譯器就會自動匹配var變量的實際類型,並用實際類型來替換該變量的聲明,等同於我們在編碼時使用了實際類型聲明。而dynamic被編譯后是一個Object類型,編譯器編譯時不會對dynamic進行類型檢查。
    3. 再說說Object,上面提到dynamic類型再編譯后是一個Object類型,同樣是Object類型,那么兩者的區別是什么呢?
    4. 除了在編譯時是否進行類型檢查之外,另外一個重要的區別就是類型轉化,這也是dynamic很有價值的地方,dynamic類型的實例和其他類型的實例間的轉換是很簡單的,開發人員能夠很方便地在dyanmic和非dynamic行為間切換。任何實例都能隱式轉換為dynamic類型實例,見下面的例子:
    dynamic d1 = 7;
    dynamic d2 = "a string";
    dynamic d3 = System.DateTime.Today;
    dynamic d4 = System.Diagnostics.Process.GetProcesses();
    
    1. 反之亦然,類型為dynamic的任何表達式也能夠隱式轉換為其他類型。
    int i = d1;
    string str = d2;
    DateTime dt = d3;
    System.Diagnostics.Process[] procs = d4;
    

前面整理過一篇關於dynamic類型與Newtonsoft.Json來操作請求的數據,請參考如下文章


參考Nettonsoft.Json中的訪問,同樣定義一個JTextAccessor,代碼如下

dynamic是C#里面的動態類型,可在未知類型的情況訪問對應的屬性,非常靈活和方便。
如果有已知對應的強類型,可以直接轉成對應的類型。但如果沒有,要訪問Json里面對應的數據的時候,就顯得比較麻煩。再根據Asp.Net Core WebAPI中的FromBody傳遞內容就是一個JsonElement,我們可以借助DynamicObject來方便的訪問對應的屬性。

public class JTextAccessor : DynamicObject
{
    private readonly JsonElement _content;

    public JTextAccessor(JsonElement content)
    {
        _content = content;
    }

    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        result = null;
        if (_content.TryGetProperty(binder.Name, out JsonElement value))
        {
            result = Obtain(value);
        }
        else return false;
        return true;
    }

    private object Obtain(in JsonElement element)
    {
        switch (element.ValueKind)
        {
            case JsonValueKind.String: return element.GetString();
            case JsonValueKind.Null: return null;
            case JsonValueKind.False: return false;
            case JsonValueKind.True: return true;
            case JsonValueKind.Number: return element.GetDouble();
            default: break;
        }

        if (element.ValueKind == JsonValueKind.Array)
        {
            var list = new List<object>();
            foreach (var item in element.EnumerateArray())
            {
                list.Add(Obtain(item));
            }

            return list;
        }
        // Undefine、Object
        else return new JTextAccessor(element);
    }
}

編寫一個Controller來驗證

// POST api/<ShyzController>
[HttpPost]
public IActionResult Post([FromBody] JsonElement value)
{
    dynamic ja = new JTextAccessor(value);
    string reqCode = ja.reqCode;
    string Name = ja.Name;
    int Age = (int)ja.Age;
    var list = ja.List;
    string childName = list[0].Name;
    string phoneNumber = ja.Data.Content;
    string str = JsonSerializer.Serialize(value);
    _logger.LogInformation(str);
    return Ok(new
              {
                  code = "0",
                  message = "成功",
                  reqCode = reqCode
              });
}

設置好斷點,調試

  • 調試斷點

  • 使用postman做請求測試

  • 查看調試的結果非常理想,成功偷懶省了事


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM