靜中有動-動態類型

来源:http://www.cnblogs.com/Helius/archive/2016/08/21/5792997.html
-Advertisement-
Play Games

在C#4.0中,最核心的特性莫過於動態類型的引入。 1、動態類型簡介 一直在強調C#是一門靜態類型的語言,因為它在定義變數時要明確給出變數的類型。例如在int i=5;這樣的代碼中,int就是變數i的類型,如果定義變數時沒有明確指定變數的類型,則這樣的代碼是通過不了編譯的。 在C#4.0中,微軟引入 ...


在C#4.0中,最核心的特性莫過於動態類型的引入。

1、動態類型簡介

    一直在強調C#是一門靜態類型的語言,因為它在定義變數時要明確給出變數的類型。例如在int i=5;這樣的代碼中,int就是變數i的類型,如果定義變數時沒有明確指定變數的類型,則這樣的代碼是通過不了編譯的。

    在C#4.0中,微軟引入了dynamic關鍵字來定義動態類型。當我們使用由dynamic關鍵字限制的變數時,編譯器並不知道它的類型,該類型只能在程式運行的時候才能被確定。動態類型的定義如下麵的代碼所示:

    dynamic i=5;

    從上面這行代碼可以看出,定義動態類型的過程非常簡單,只需要把之前的int類型修改為dynamic關鍵字即可。

    那靜態類型和動態類型到底有什麼不同呢?以代碼來說明:

    object obj=10;

    obj=obj+10;//編譯錯誤

    dynamic i=10;//動態類型定義

     i=i+10;

    在以上的代碼中,第一行obj為object類型,而編譯器卻檢測出“+”運算符無法應用於object和int類型。要讓代碼通過編譯,必須使用強制類型轉換。動態類型定義就不需要轉換了,動態類型定義的變數的具體類型只能在程式運行時被確定,編譯器根本不知道其類型是什麼,所以也就不會出現編譯錯誤了。

 

2、C#為什麼要引入動態類型

     2.1 可以減少強制類型轉換的使用

     2.2 調用Python等動態語言

           動態類型使得C#語言調用Python這樣的動態語言成為了可能。比如:

1 ScriptEngine engine=Python.CreateEngine();
2 Console.WriteLine("調用Python語言的print函數輸出:");
3 engine.Execute("print 'Hello world'");
4 Console.Read();

    以上代碼實現了在C#中調用Python的print函數完成消息列印的過程,但要使這段代碼能夠運行,還必須下載IronPython。IronPython是在.NET Framework上實現的一種動態語言。

    由於動態類型變數的具體類型只能在運行時確定,所以智能提示對於動態類型變數並不管用。開發人員在使用動態類型時,必須準確地知道類型所具有的成員,否則在程式運行時很難發現相關錯誤。

 

3、動態類型約束

    動態類型的使用需要滿足一下幾個約束條件:

    3.1 不能用來調用擴展方法

          不能用動態類型作為參數來調用擴展方法,例如下麵的代碼將導致編譯錯誤:

           var numbers=Enumerable.Range(10,10);

           dynamic number=4;

           var error=numbers.Take(number);//編譯錯誤

           出現這種錯誤的原因在於:擴展方法是在另一個文件中被定義的,若參數為動態類型,編譯器將無法確定參數的具體類型,因為也就不知道該導入哪個源文件了。我們可以通過兩個方法來解決這個問題:

           第一種是將動態類型強制轉換為正確的類型:var right1=numbers.Take((int)number);

           第二種是使用靜態方法來調用擴展方法:var right2=Enumerable.Take(numbers,number);

           這兩種方法雖然都可能,但還是不推薦在調用擴展方法時使用動態類型。

 

    3.2 委托與動態類型間不能做隱式轉換

          不能將Lambda表達式定義為動態類型,因為他們之間不存在隱式轉換,如下麵的代碼就會出現編譯錯誤:

          dynamic lambdarestrict=x=>x+1;//編譯時錯誤

          如果硬要把Lambda表達式定義為動態類型,就需要明確指定委托的類型,具體的解決方案如下:

          dynamic rightLambda=(Func<int,int>)(x=>x+1);

 

    3.3 不能調用構造函數和靜態方法

          dynamic s=new dynamic();//編譯錯誤   因為此時編譯器無法指定具體的類型。

 

    3.4 類型聲明和泛型類型參數

          不能將dynamic關鍵字用來基類聲明,也不能將dynamic用於類型參數的約束,或作為類型所實現的介面的一部分。具體的實例代碼如下:

 1 class DynamicBaseType:dynamic //基類不能為dynamic類型
 2 {
 3 }
 4 
 5 class DynamicTypeConstrain<T> where T:dynamic //dynamic類型不能用作類型參數
 6 {
 7 }
 8 
 9 class DynamicInterface :IEnumerable<dynamic>//dynamic不能作為所實現介面的一部分
10 {
11 }

 

4、實現自己的動態行為

    引入靜態類型後,我們便可為類型動態地添加屬性和方法,從而實現我們自己的動態行為。具體來說,.NET中支持3種實現動態行為的方式:

    (1)使用ExpandoObject;

    (2)使用DynamicObject;

    (3)實現IDynamicMetaObjectProvider介面

 

    4.1 使用ExpandoObject來實現動態行為

         ExpandoObject是實現動態行為的最簡單的方式,其實現代碼如下:

         

 1 using System;
 2 using System.Dynamic;
 3 
 4 namespace 動態類型
 5 {
 6     class Program
 7     {
 8         static void Main(string[] args)
 9         {
10             dynamic expand = new ExpandoObject();
11             //動態綁定成員
12             expand.Name = "Helius";
13             expand.Age = 24;
14             expand.Addmethod = (Func<int, int>) (x => x + 1);
15             //調用類型成員
16             Console.WriteLine($"enpand類型的姓名為:{expand.Name},年齡為:{expand.Age}");
17             Console.WriteLine($"調用expand類型的動態幫東方法:{expand.Addmethod(5)}");
18             Console.ReadKey();
19         }
20     }
21 }

    以上代碼通過使用ExpandoObject類,動態地為expand動態類型添加了屬性和函數,並且expand類型也可以成功地被調用。

 

    4.2 使用DynamicObject來實現動態行為

         除了使用ExpandoObject,我們還可以通過重寫DynamicObject來實現動態行為,具體的實現代碼如下:

          

 1 using System;
 2 using System.Dynamic;
 3 
 4 namespace 動態類型
 5 {
 6     class Program
 7     {
 8         static void Main(string[] args)
 9         {
10             dynamic dynamicobj=new DynamicType();
11             dynamicobj.CallMethod();
12             dynamicobj.Name = "Helius";
13             dynamicobj.Age = 24;
14             Console.ReadKey();
15         }
16     }
17 
18 
19     class DynamicType:DynamicObject
20     {
21         //重寫TryXXX方法,該方法表示對對象進行動態調用
22         public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
23         {
24             Console.WriteLine($"{binder.Name}方法正在被調用");
25             result = null;
26             return true;
27         }
28 
29         public override bool TrySetMember(SetMemberBinder binder, object value)
30         {
31             Console.WriteLine($"{binder.Name} 屬性被設置,設置的值為{value}");
32             return true;
33         }
34     }
35 }

    

    4.3 使用IDynamicMetaObjectProvider介面來實現動態行為

          由於Dynamic類型是在運行過程中動態創建對象的,所以在對該類型的每個成員進行訪問時,都會首先調用GetMethodObject方法來獲得動態對象,然後再通過這個動態對象來完成調用。因為為了實現IDynamicMetaObjectProvider介面,我們需要先實現一個GetMetaObject方法,用以返回DynamicMetaObject對象。

      

 1 using System;
 2 using System.Dynamic;
 3 using System.Linq.Expressions;
 4 
 5 namespace 動態類型
 6 {
 7     class Program
 8     {
 9         static void Main(string[] args)
10         {
11 
12             dynamic dynamicObj2=new DynamicType2();
13             dynamicObj2.Call();
14             Console.ReadKey();
15         }
16     }
17 
18 
19     class DynamicType:DynamicObject
20     {
21         //重寫TryXXX方法,該方法表示對對象進行動態調用
22         public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
23         {
24             Console.WriteLine($"{binder.Name}方法正在被調用");
25             result = null;
26             return true;
27         }
28 
29         public override bool TrySetMember(SetMemberBinder binder, object value)
30         {
31             Console.WriteLine($"{binder.Name} 屬性被設置,設置的值為{value}");
32             return true;
33         }
34     }
35 
36 
37     internal class DynamicType2 : IDynamicMetaObjectProvider
38     {
39         public DynamicMetaObject GetMetaObject(Expression parameter)
40         {
41             Console.WriteLine("開始獲得元數據......");
42             return new Metadynamic(parameter, this);
43         }
44     }
45 
46     internal class Metadynamic : DynamicMetaObject
47     {
48         internal Metadynamic(Expression expression, DynamicType2 value):base(expression,BindingRestrictions.Empty,value)
49         {
50         }
51 
52         public override DynamicMetaObject BindInvokeMember(InvokeMemberBinder binder, DynamicMetaObject[] args)
53         {
54             //獲得真正的對象
55             DynamicType2 target = (DynamicType2) base.Value;
56             Expression self = Expression.Convert(base.Expression, typeof (DynamicType2));
57             var restrictions = BindingRestrictions.GetInstanceRestriction(self, target);
58             //輸出綁定方法名
59             Console.WriteLine($"{binder.Name} 方法被調用了");
60             return new DynamicMetaObject(self,restrictions);
61         }
62     }
63 }

    結果為:

    

          


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

-Advertisement-
Play Games
更多相關文章
  • RT 1.這裡解釋幾個主要的子函數,首先是task_timeslice,重新計算時間片。首先介紹一下基本時間片的概念。 靜態優先順序本質上決定了進程的基本時間片,即進程用完了以前的時間片時,系統分配給進程的時間片長度。靜態優先順序和基本時間片的關係用下列公式確定: 如你所見,靜態優先順序越高(其值越小), ...
  • 我準備安裝到/usr/local目錄下 1. cd /usr/local 2. 安裝GCC 和GCC-C++ yum install gcc yum install -y gcc gcc-c++ 3. 安裝pcre庫 cd /usr/local/wget ftp://ftp.csx.cam.ac.u ...
  • 原文地址:http://ncforest.blog.163.com/blog/static/295626642007551417331/ 1.sudo的配置文件是/etc/sudoers ,我們可以用他的專用編輯工具visodu ,此工具的好處是在添加規則不太準確時,保存退出時會提示給我們錯誤信息; ...
  • 摘自:http://www.apelearn.com/bbs/thread-7467-1-1.html 一. 使用 su 命令臨時切換用戶身份 1、su 的適用條件和威力 su命令就是切換用戶的工具,怎麼理解呢?比如我們以普通用戶beinan登錄的,但要添加用戶任務,執行useradd ,beina ...
  • kali的openvas安裝 留下筆記,以便下次再查開始在kali找openvas,竟然kali不自帶,害的要下載。 apt-get updateapt-get dist-upgradeapt-get install openvas (我記得大約要下600M左右)安裝完後openvas-setupo ...
  • 背水一戰 Windows 10 之 控制項(文本類): RichTextBlock, RichTextBlockOverflow, RichEditBox ...
  • 本篇文章版權歸博客園和作者吳雙本人共同所有,轉載和爬蟲請註明原文系列地址http://www.cnblogs.com/tdws/tag/NoSql/ 本人之前有篇文章,講到了redis主從複製,讀寫分離。然而留下的問題是當主伺服器掛了,我們就無法向客戶端提供任何服務了呀,這樣的方案,就不能稱之為高可 ...
  • 原文網址: http://www.cnblogs.com/csdev Networkcomms 是一款C# 語言編寫的TCP/UDP通信框架 作者是英國人 以前是收費的 目前作者已經開源 開源地址是:https://github.com/MarcFletcher/NetworkComms.Net 這 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...