C#.net 提供的4個關鍵字,in,out,ref,paras開發中會常用到,那麼它們如何使用呢? 又有什麼區別?
範例:
//测试模型 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。可知,可以修改物件的屬性。
1)帶有out的形參,在函數定義時,return前必須給函數賦一個值。
2)呼叫函數時,帶有out的參數不必賦一個初始值。
3)out形參傳值是透過引用(by reference)
在函數傳回多個值時,通常會用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模式
例如:
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); // ...}
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: TKey The 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 Paras5.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),帶有這個參數的函數,只需要一個版本,這樣解決了因為個數不一致而導致的多個重載版本,
在客戶端調用時,將屬性參數一一列數即可。
C#.net 提供的4個關鍵字,in,out,ref,paras開發中會常用到,那麼它們如何使用呢? 又有什麼區別?
以上就是C# in ,out, ref , paras用處的詳細介紹的內容,更多相關內容請關注PHP中文網(www.php.cn)!