国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

編寫高質量代碼改善C#程序的157個建議[動態數組、循環遍歷、對象集合初始化]

2019-11-17 03:15:14
字體:
來源:轉載
供稿:網友

編寫高質量代碼改善C#程序的157個建議[動態數組、循環遍歷、對象集合初始化]

前言

  軟件開發過程中,不可避免會用到集合,C#中的集合表現為數組和若干集合類。不管是數組還是集合類,它們都有各自的優缺點。如何使用好集合是我們在開發過程中必須掌握的技巧。不要小看這些技巧,一旦在開發中使用了錯誤的集合或針對集合的方法,應用程序將會背離你的預想而運行。

  本文已更新至http://m.survivalescaperooms.com/aehyok/p/3624579.html。本文主要學習記錄以下內容:

  建議16、元素數量可變的情況下不應使用數組

  建議17、在多數情況下使用foreach進行循環遍歷

  建議18、foreach不能代替for

  建議19、使用更有效的對象和集合初始化

建議16、元素數量可變的情況下不應使用數組

  在C#中,數組一旦被創建,長度就不能改變。如果我們需要一個動態且可變長度的集合,就應該使用ArrayList或List<T>來創建。而數組本身,尤其是一維數組,在遇到要求高效率的算法時,則會專門被優化以提升其效率。一維數組也成為向量,其性能是最佳的,在IL中使用了專門的指令來處理它們。

  從內存使用的角度來講,數組具有以下特點:

  1、數組在創建時被分配了一段固定長度的內存。

  2、如果數組元素是值類型,則每個元素的長度等于相應的值類型的長度

  3、如果數組的元素是引用類型,則每個元素的長度為該引用類型的IntPtr.Size。

  4、數組的存儲結構一旦被分配,就不能再變化。

  而ArryaList是這樣的:

  1、ArrayList是鏈表結構,可以動態增減內存空間。

  2、如果ArrayList存儲的是值類型,則會為每個元素增加12字節的空間,其中4字節用于對象引用,8字節是元素裝箱時引入的對象頭。

  而List<T>是ArrayList的泛型實現,它省去了拆箱和裝箱帶來的開銷。

如果一定要動態改變數組的長度,一種方法是將數組轉換為ArrayList或List<T>,如下面的代碼所示:

            ///定義一個一維數組            int[] iArr = { 0,1,3,4,6,7,9};            ///將數組轉換為ArrayList            ArrayList arrayListInt = ArrayList.Adapter(iArr);            arrayListInt.Add(11);            ///將數組轉換為List<T>            List<int> listInt = iArr.ToList<int>();            listInt.Add(11);

  還有一種方法是用數組的復制功能。數組繼承自System.Array,抽象類System.Array提供了一些有用的實現方法,其中就包含了Copy方法,它負責將一個數組的內容復制到另外一個數組中。無論是哪種方法,改變數組長度就相當于重新創建了一個數組對象。

  為了讓數組看上去本身就具有動態改變長度的功能,還可以創建一個名為ReSize的擴展方法。

    public static class ClassForExtensions    {        public static Array ReSize(this Array array,int newSize)        {            Type t = array.GetType().GetElementType();            Array newArray = Array.CreateInstance(t, newSize);            Array.Copy(array, 0, newArray, 0, Math.Min(array.Length, newSize));            return newArray;        }    }

調用方式如下:

        static void Main(string[] args)        {            int[] iArr = { 0,1,3,4,6,7,9};            iArr = (int[])ClassForExtensions.ReSize(iArr, 20);            Console.ReadLine();        }

下面我們來對比一下性能,先來看代碼:

    class PRogram    {        static void Main(string[] args)        {            ResizeArray();            ResizeList();            Console.ReadLine();        }        public static void ResizeArray()        {            int[] iArr = {0,1,3,4,6,8 };            Stopwatch watch = new Stopwatch();            watch.Start();///用于測量時間間隔            iArr = (int[])iArr.ReSize(10);            watch.Stop();///            Console.WriteLine("ResizeArray:{0}", watch.Elapsed);        }        public static void ResizeList()        {            List<int> iArr = new List<int>(new int[] { 0, 1, 3, 4, 6, 8, 9 });            Stopwatch watch = new Stopwatch();            watch.Start();            iArr.Add(0);            iArr.Add(0);            iArr.Add(0);            watch.Stop();            Console.WriteLine("ResizeList:{0}", watch.Elapsed);        }    }

Main函數中主要是調用,自己定義的兩個方法,第一個是重新設置數組的長度,第二個是設置List<T>的長度,通過運行時間進行測量:

嚴格意義上講,List<T>不存在改變長度的說法,此處主要是來進行對比一下,對List<T>設置長度,并且進行賦值,即便是這樣,在時間效率上ResizeList比ResizeArray要高很多很多。

建議17、在多數情況下使用foreach進行循環遍歷

這里關于如何針對集合才能使用foreach進行遍歷我剛剛寫了一篇有關IEnumerable和IEnumerator兩個接口的文章,有興趣的話可以看一下。http://m.survivalescaperooms.com/aehyok/p/3641193.html

感覺使用foreach進行循環遍歷,總共有三個好處吧:

1、提供了比較簡單、簡潔的語法。

2、自動將代碼置入try-finally塊

3、若類型實現IDispose接口,foreach會在循環結束后自動調用Dispose方法

建議18、foreach不能代替for

foreach存在一個問題是:它不支持循環時對集合進行增刪操作。我們來看一下簡單的例子:

            List<int> list = new List<int>() { 1, 2, 3, 4, 5 };            foreach (int item in list)            {                list.Remove(item);                Console.WriteLine(item.ToString());            }            Console.ReadLine();

一起看一下執行結果:

那么下面我們來使用for進行嘗試:

            List<int> list = new List<int>() { 1, 2, 3, 4, 5 };            for (int i = 0; i < list.Count(); i++)            {                list.Remove(list[i]);            }            Console.ReadLine();

  進行刪除肯定是沒問題的。但是要仔細看一下,比如它第一次刪除索引0的時候,也就是刪除了1,那么它會立即重新調整索引,然后第二次刪除的時候,刪除的不是2,而是3這個項。那么最終運行完發現還剩余兩項

 foreach循環使用了迭代器進行集合的遍歷,它在FCL提供的迭代器內部維護了一個對集合版本的控制。那么什么是集合版本呢?簡單的說,其實它就是一個整型的變量,任何對集合的增刪操作都會使版本號加1。foreach循環會調用MoveNext方法來遍歷元素,在MoveNext方法內部會進行版本號的檢測,一旦檢測到版本號有變動,就會拋出InvalidOperationException異常。

如果使用for循環就不會帶來這樣的問題。for直接使用所引器,它不對集合版本號進行判斷,所以不存在因為集合的變動而帶來的異常(當然,超出索引長度這種情況除外)。

  索引,因為版本檢測的緣故,foreach循環并不能帶起for循環。 

建議19、使用更有效的對象和集合初始化

  對象初始化設定項支持可以直接在大括號中對自動實現的屬性進行賦值。

    class Person    {        public string Name { get; set; }        public int Age { get; set; }    }    class Program    {        static void Main(string[] args)        {            Person person = new Person() { Name = "aehyok", Age = 25 };            Console.ReadLine();        }    }

以往只能依靠構造方法傳值進去,或者在對象構造完畢后對屬性進行賦值。現在這些步驟簡化了,初始化設定項實際相當于編譯器在對象生成后對屬性進行了賦值。

    class Person    {        public string Name { get; set; }        public int Age { get; set; }    }    class Program    {        static void Main(string[] args)        {            Person person = new Person() { Name = "Kris", Age = 22 };            List<Person> personList = new List<Person>()            {                 new Person() { Name = "aehyok", Age = 25 },                person,                null            };            Console.ReadLine();        }    }

使用集合的初始化設定項,編譯器會在集合對象創建完畢后對集合調用Add方法。上面這段代碼展示了如何在初始化語句中創建一個新對象或一個現有對象,以及一個null值。

不過,初始化設定項絕不僅僅是為了對象和集合初始化的方便,它更重要的作用是為LINQ查詢中的匿名類型進行屬性的初始化。由于LINQ查詢返回的集合中匿名類型的屬性都是只讀的,如果需要為匿名類型屬性賦值,或者增加屬性,只能通過初始化設定項來進行。初始化設定項還能為屬性使用表達式。

來看一段代碼:

List<Person> lst = new List<Person>() {     new Person(){ Age = 10,Name="Tommy"},    new Person(){ Age = 20,Name="Sammy"} };var entity = from p in lst             select new { p.Name, AgeScope = p.Age > 10 ? "Old" : "Young" };foreach (var item in entity){   Response.Write(string.Format("name is {0},{1}", item.Name, item.AgeScope));}

AgeScope 屬性是經過計算得出的,有了如此方便的初始化方式,使得代碼更加優雅靈活。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 朔州市| 望奎县| 岳西县| 西藏| 浏阳市| 德安县| 武城县| 桂阳县| 泽州县| 民丰县| 和硕县| 姜堰市| 揭东县| 旺苍县| 波密县| 鄱阳县| 长兴县| 扎鲁特旗| 吕梁市| 西和县| 雷州市| 连州市| 井陉县| 安化县| 南宫市| 余干县| 崇仁县| 新源县| 石楼县| 长阳| 河北省| 大同市| 黑山县| 深泽县| 泸溪县| 高阳县| 新沂市| 巫山县| 柯坪县| 晋宁县| 金溪县|