.NET架構- in ,out, ref , paras使用的代碼總結

來源:互聯網
上載者:User
C#.net 提供的4個關鍵字,in,out,ref,paras開發中會經常用到,那麼它們如何使用呢? 又有什麼區別?

1 in

in只用在委託和介面中;
例子:

       //測試模型       class Model        {                    public int a { get; set; }                    public Model(int a)            {                            this.a = a;            }        }//建立3個執行個體List<Model> modelList= new List<Model>() { new Model(1), new Model(4), new Model(6) };//調用foreach介面,試著操作3個執行個體,賦值為nullmodelList.ForEach(e=>e=null); //查看結果://modelList的取值不變。

分析原因,ForEach的參數是委託函數:

//ForEach方法:public void ForEach(Action<T> action);//委託聲明:public delegate void Action<in T>(T obj);

委託是泛型的,類型T前加了一個關鍵字in,因為帶有關鍵字in,所以T obj是不能被修改的。

嘗試測試:

//修改元素e的屬性amodelList.ForEach(e=>{e.a*=2;});

結果每個元素都乘以2,變為2,8,12。可知,可以修改對象的屬性。

2 out

out 關鍵字用法注意:
1)帶有out的形參,在函數定義時,return前必須給函數賦一個值。
2)調用函數時,帶有out的參數不必賦一個初始值。
3)out形參傳值是通過引用(by reference)

out使用情境:
在函數返回多個值時,通常用out 返回其中一個

public bool Operation(out Model updateMod){    updateMode = new Model(5);        try{         // my operation     ...          //     return true;    }    catch{      //寫入日誌      return false;    }}//使用Model um; //未初始化bool rtnMsg = Operation(out um); //如果初始化,傳值通過reference//分析://返回um,如果rntMsg為ture,則um按照預想邏輯被賦值,//如果rntMsg為false 則um未按照預想邏輯被賦值。

C#.net中有一類TryParse函數,便是out的另一個重要應用。若感興趣,請見:透過Parse和TryParse:Try-Parse和Tester-Doer模式

3 ref

ref關鍵字用於改變參數傳遞,將by value修改為by reference傳值,原來是by reference傳遞的,加上ref還是不加ref,效果是一樣的。

例如:

public void reviseModel(int a){  a = 12;}Model model = new Model(10);//調用reviseModelreviseModel(model.a); //model.a仍然=10;by-valuereviseMode(ref model.a); //編譯不過,提示ref後的參數不歸類與變數int a;reviseMode(ref a); //如果不給變數a賦一個初始值,//編譯器也是提示:調用前未被賦值的錯誤//因此賦值int a= model.a; //變數a初始值為10;reviseMode(ref a);//修改變數a=12;但是model.a的值仍然為10

如何修改對象model中的屬性a,將其變為12呢?

//直接將參數設為Model對象,則函數調用時,傳值通過by referencepublic void reviseModel(Model md){  md.a = 12;}reviseModel(model );//傳值通過by reference

因此,ref關鍵詞使用總結:
ref的話,用於處理值變數,如基本類型、結構等,它們不需要被new出來,傳值依照的是值拷貝。

1)ref 後的變數,如果是實值型別(value type),那麼加上ref後變為按照 by reference傳值;

2)ref 後的變數,如果是參考型別(reference type),那麼加上ref與不加沒有任何區別;

3)ref後的變數,使用前必須賦值

4)ref後的變數不能是參考型別的屬性

以上是基本的分析,在使用中就夠了,如果想更深入的分析這個問題,請繼續。

4 深入探討out ref

主要分析out ref 到底有何用,不用他們會有什麼影響。

1) C#中有一類方法,名字叫作Try…,如Int.TryParse,它返回一個bool值,嘗試解析一個字串,如果成功解析為整數,則返回true,得到的整數作為第二個out的int被傳出。
見分析文章
異常設計準則
透過Parse和TryParse:Try-Parse和Tester-Doer模式
從文章中看出,相比沒有out參數的次方法Parse,如果解析字串失敗,則會拋出一個參數錯誤的異常。

用Try…方法寫出來的代碼比try…catch寫出來的要簡潔,於是這也變成了out參數使用的一個常用情境。

2) Java和C#比較

在Java裡,HashMap

// HashMap<K, V> map;// K key;V val = map.get(key);if (val != null) {  // ...}

但val == null,既可能是該map裡尚未有鍵為該key的索引值對,也可能是已經有該索引值對了但是其值為null。
要區分兩者,HashMap提供了containsKey()方法。所以正確的寫法是這樣的:

// HashMap<K, V> map;// K key;if (map.containsKey(key)) {  V val = map.get(key);  // ...}

containsKey()跟get()的內部操作幾乎是一模一樣的,都要做一次hash尋找,只是返回了尋找結果的不同部分而已。也就是說按照這種“正確寫法”來寫的話,訪問一次HashMap就有雙倍開銷了。杯具!

C#有許多這種細節設計比Java更貼心。看C#用out關鍵詞如何改進這個問題。

System.Collections.Generic.Dictionary

TryGetValue:Dictionary(TKey, TValue).TryGetValue Method (TKey, TValue) (System.Collections.Generic)public bool TryGetValue(    TKey key,    out TValue value)ParameterskeyType: TKeyThe key of the value to get.valueType: TValue

利用這個方法,上面的Java代碼對應的C#版就可以寫成:

// Dictionary<TKey, TValue> dict;// TKey key;TValue val;if (dict.TryGetValue(key, out val)) {  // ...}

這就把ContainsKey與Item[Key]的語義結合了起來,把一次hash尋找能找到的資訊一口氣都返回出來,從源頭上避免了“兩次尋找”的冗餘操作,有利於程式的效能。

C#.net中提供了一個關鍵字 params,以前都不知道有這個關鍵字,有一次,同事看到我的幾版重載函數後,淡定地和我說了一句,哥呀,你可以用params,後來查了查,現在經常用習慣了,這不剛才又把之前寫的幾版都拿掉了,又用params重構了下。

5 Paras

那麼,我就把params的用處,我經曆的這個過程說一下。

5.1 問題的需求
在用戶端,客戶經常會變動查詢的欄位,前幾天還是根據4個關鍵字段去伺服器查詢幾個模型呢,今天,又想加1個查詢欄位。

根據4個關鍵字段的查詢方法:

        public void GetPlansByInputControl(string planState, string contactno,DatePair dp)        {                   string planStat = "";                        switch (planState)            {                            case "...":                    planStat = "...";                                        break;                                    case "...":                    planStat = "...";                                        break;            }                plans = getPlansWithCondition(Convert.ToDateTime(dp.startValue), Convert.ToDateTime(dp.endValue), planStat, contactno);        }

調用的getPlansWithCondition方法為

        private List<MPartPlan> getMPartPlansWithCondition(DateTime dateTime,         DateTime dateEndTime, string planStat, string contactNo)        {            var conditions = new CslSqlBaseSingleTable();            conditions.AddCondition("RequireStartDate", dateTime, DataCompareType.GreaterOrEqual);            conditions.AddCondition("RequireStartDate", dateEndTime, DataCompareType.LessOrEqual);            conditions.AddCondition("OrderCode", contactNo, DataCompareType.Equal);                        if (!string.IsNullOrEmpty(planStat))            {                conditions.AddCondition("PlanState", planStat, DataCompareType.Equal);            }                        return _cslMPartPlan.QueryListInSingleTable(typeof(MPartPlan), conditions);        }        }

問題來了,當查詢再新加1個欄位時,你難道還再重載一個版本嗎?

5.2 應用params

 private List<MPartPlan> getMPartPlansWithCondition(DateTime dateTime, DateTime dateEndTime, string planStat, string contactNo,string newField);

當C#提供了params後,當然不用,直接將getMPartPlansWithCondition改寫為如下

private List<MPartPlan> getMPartPlansWithCondition(params object[] queryConditions);{   queryConditions[0]   queryConditions[1]   queryConditions[2]   queryConditions[3]   queryConditions[4]   //放到字典中dict   sqlQuery(dict);}

以後隨意添加查詢欄位,只要修改下這個函數就行了,不用增刪重載版本!!!

用戶端調用,直接加一個欄位就行

_bsl.GetPlansByInputControl(field1, field2,field3,field4,field5);

5.3 總結

queryFun(params object[] objs),帶有這個參數的函數,只需要一個版本,這樣解決了因為個數不一致而導致的多個重載版本,
在用戶端調用時,將屬性參數一一列數即可。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.