C#4.0之dynamic的使用

在上一篇有關.Net 輕量 ORM Dapper 的介紹中咱們提出了兩個疑問,其中之一就是怎麼讓 Dapper 查詢傳參可變的問題,固然這裏主要說是個數可變。這裏咱們就介紹C#4.0的新特性之一—— dynamic 。javascript

C#4.0經常使用新特性

C#4.0引入了不少新特性方便咱們進行開發,其中經常使用的包含如下四種。
  1. 可選參數
    爲方法的參數設定默認值,標識它是可選的,
            public static void Show(string str1="str1",string str2="str2")
            {
                Console.WriteLine(str1 + str2);
            }


  2. 命名參數
    上面的方法能夠像下面遮掩的
         Show(str2:"msg");
    運行結果:str1msg。當你的方法有多個同一類型的可選參數(optional parameters)時,命名參數(Named parameters)特別有用。若是不用命名參數,編譯器會把傳參賦給第一個符合類型的參數,運行結果就會是:msgstr2。
  3. Dynamic 特性
    dynamic關鍵字用於聲明一個動態對象,而後經過該動態對象去調用方法或讀寫屬性。之前咱們都是在運行時經過反射,Emit,CodeDom等技術來完成。建立一個dynamic類型的對象須要使用一個特殊的構建器叫ExpandoObject。
                dynamic person = new System.Dynamic.ExpandoObject();
    
                person.Name = "cary";
    
                person.Age = 25;
    
                person.ShowDescription = new Func<string>(() => person.Name + person.Age);
    
     
    
                Console.WriteLine(person.Name+person.Age+person.ShowDescription());           
    
                Console.ReadLine();

C#4.0之Dynamic介紹

dynamicl 類型能夠很方便的隨意插入字段、屬性、方法。dynamic的出現讓C#具備了弱語言類型的特性。dynamic類型的變量,不是在編譯時候肯定實際類型的, 而是在運行時。因此 編譯器在編譯的時候再也不對類型進行檢查,編譯期默認dynamic對象支持你想要的任何特性。也就是說諸以下面的這兩行代碼,在程序編譯時不會報錯,而是在程序運行時報錯:
dynamic a = "test";
a++;
這就要求咱們在使用 dynamic 關鍵字時要特別當心。
在上面的例子中,細心的同窗會發現 dynamic 類型須要藉助 System.Dynamic.ExpandoObject 來實現,ExpandoObject() 是另外一個重要的C#4.0特性之一,爲了探討這一特性,咱們首先來看 用dynamic加強C#泛型表達力中的一段代碼:
static class Calculator {
    public static T Add<T>(T t1, T t2) {
        dynamic d1 = t1;
        dynamic d2 = t2;

        return (T)(d1 + d2);
    }
}

public static void Main(string[] args){
    int i = Calculator.Add(1, 2);
    double d = Calculator.Add(1.1, 2.2);
    string s = Calculator.Add("abc", "def");

    Console.WriteLine(i + " " + d + " " + s);

}
做者在文中指出 C#代碼是爲了經過動態類型來實現基於duck typing的泛型參數約束。ExpandoObject 是C#支持Duck Type的根本緣由。在Visual Studio 2010 中咱們能夠看到該類的成員列表,截圖以下:

Expando
所屬方法都是虛方法,咱們能夠重寫這些虛方法。這裏主要看TryInvokeMember()方法。這個方法VS2010給出了詳細的描述。
簡單介紹一下如何使用這個方法:假設咱們一個類OurClass它繼承了DynamicObject 這個Class。OurClass中有一個方法OurMethod()。接着在OurClass 類中 重寫 TryInvokeMember這個基類虛方法。以上設置完後之後只要OurClass 的OurMethod方法一旦被調用都先執行一下重寫後的TryInvokeMember()方法。也許您會問這樣到底有何用途?OK!請先看javascript這段代碼片斷:
        function tryInvokeMember(obj) {
            if (obj && typeof obj.ourMethod === "function") {
                return obj.ourMethod();
            }
            alert('未找到!');
            return null;
        }

        var ourObj1 = {};
        ourObj1.Method = function () {
            alert('111');
        };

        var ourObj2 = {};
        ourObj2.ourMethod = function () {
            alert('已經找到ourMethod而且執行');
        };

        tryInvokeMember(ourObj1);
        tryInvokeMember(ourObj2);
你們讀完這段js代碼後應該會明白爲何我要重點討論C#4.0中的DynamicObject了吧?真正的目的就是:在DuckType 類(鴨子) 方法(鴨子叫)執行以前,咱們要判斷對象的類是不是具有鴨子叫的功能?若是不具有就不該該執行,不然程序勢必會拋出異常。C#中如何實現呢?步驟以下:
  1. 創建DynamicAnimal 類繼承DynamicObject類,而且重寫TryInvokeMember虛方法:
    <strong>    </strong>public class DynamicAnimal : DynamicObject
        {
            public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
            {
                bool success = base.TryInvokeMember(binder, args, out result);
    
                //若是方法不存在,請將result 這個out參數賦值爲null
                if (!success) 
                    result = null;
    
                //若是這個地方返回false 將會引起異常
                return true;
            }
        }
  2. 創建兩個DuckType類,分別爲Duck 和 Human:
    public class Duck : DynamicAnimal
        {
            public string Quack()
            {
                return "鴨子嘛,就Quack吧!";
            }
        }
     public class Human : DynamicAnimal
        {
            public string Talk()
            {
                return "人類是用Talk,而不是Quack";
            }
        }
  3. 在Console 內 創建DuckType的調用方法:
    public static string DoQuack(dynamic animal)
    {
        string result = animal.Quack();
        return result ?? "...人類固然不會鴨叫...";
    }
  4. Console 內 Main方法調用:
            static void Main(string[] args)
            {
                var duck = new Duck();
                var cow = new Human();
                Console.WriteLine("鴨子是Quack");
                Console.WriteLine(DoQuack(duck));
                Console.WriteLine("人類是talk");
                Console.WriteLine(DoQuack(cow));
                Console.ReadKey();
            }

    程序的執行結果以下:
    result

var、object、dynamic比較

在語法上這三者的用法很相近
var a=1;
object a=1;
dynamic c=1;
以及
var a = new string[]{"1"};
object b = new string[]{"1"};
dynamic c = new string[]{"1"};
比較一下有助於記憶。
var是C# 3中引入的,其實它僅僅只是一個語法糖. var自己並非一種類型, 其它二者object和dynamic是類型。var聲明的變量在賦值的那一刻,就已經決定了它是什麼類型。因此若是你這樣使用,就會有編譯錯誤:
var a = 1;
a = "Test";
object之因此可以被賦值爲任意類型的緣由,其實都知道,由於全部的類型都派生自object. 因此它能夠賦值爲任何類型:
object a = 1;
a = "Test";
dynamic是C#引入的新類型,它的特色是申明爲dynamic類型的變量,不是在編譯時候肯定實際類型的, 而是在運行時。因此下面的代碼是可以經過編譯的,可是會在運行時報錯:
dynamic a = "test";
a++;
上面代碼內部處理的過程是怎樣的呢?首先, dynamic類型賦值爲字符串"test", 運行++操做的時候,.net會去尋找當前的賦值類型string中是否支持++操做,發現不支持,出現異常。因此,若是這樣修改一下,就可讓代碼正常運行起來。
dynamic a = "test";
a = 1;
a++;

結語

以上的探討是從使用角度出發對 C#4.0 新特性 dynamic 進行的介紹,若要對 dynamic 有更全面的理解,能夠移步微軟的msdn官方文檔上查看 dynamic 更專業的介紹。
傳送門:
參考博客:
相關文章
相關標籤/搜索