首頁 > 軟體

C# 迭代器分部類與索引器詳情

2022-07-18 14:04:11

1、迭代器

  • 迭代器(iterator)解決的是集合存取的問題,提供一種方法順序存取一個集合物件中的各個元素,而不暴露物件內部標識。迭代器還有一個別名:遊標(cursor)
  • foreach語句與迭代器的關係:Foreach迴圈語句可以用來迭代列舉的集合中的所有元素,又稱foreach迭代語句
  • 可列舉的:C#中,如果某個型別繼承了介面IEnumerable,或者繼承了泛型介面IEnumerable或者繼承了泛型介面IEnumerable的任何構造型別,那麼久成這個型別時可列舉的
  • 常見的可列舉型別:集合,陣列,字串類String,標識動態列表的泛型類List等

  • Foreach語句可以簡化C#內建迭代器的使用複雜性,編譯froeach語句,會生成呼叫GetEnumerator和MoveNext方法以及Current屬性的程式碼,這些方法和屬性恰是C#內建迭代器所提供的。
  • ILDASM外部工具的新增方法(中間語言反組合的工具)

方法1:

開啟新新增的外部工具:

方法2

檢視Foreach執行中間語言

  • 中間語言:intermediate language
  • ILDASM: intermediate language decompile assembly

foreach實現過程總結

foreach語句是微軟提供的支援內建迭代器的語句法糖,編譯foreach語句後生產的程式碼與使用迭代器的程式碼完全一致
呼叫GetEnumerator()方法獲得迭代器——呼叫IEnumerator.MoveNext()——呼叫IEnumerator.Current()

Foreach迴圈迭代可列舉型別的過程:

1、通過呼叫IEnumerator介面和IEnumerator的參照
2、IEnuerator呼叫MoveNext方法
3) ①True:IEnumerator的Current屬性獲取物件的應用,用於foreach迴圈
②false 結束
4、重複2、3步知道MoveNext返回false

實現迭代器最常用的方法

迭代器可用於方法、屬性存取器或其他程式碼塊,使使用者能夠在類或結構中支援Foreach迭代,而不必實現整個IEnumerable介面,只需要一個型別化的方法GetEnumerator(),不需要處理設計模式

  • 迭代器是C#可以提供的最簡單的設計模式。
  • 設計模式(Design pattern/behavorial pattern)是一套被反覆使用、多數人知曉的、經過分類編目的、典賣設計經驗總結。使用設計模式是為了可重用程式碼、讓程式碼更容易被他人理解、保證程式碼可靠性。
  • .Net Framework有自己的IEnumerator介面,使用的迭代器的作用很明確,及可以做到不暴露集合的內部介面,又可讓外部程式碼同名地方存取集合內部的資料。 2.1 建立迭代器最常用的方法 是對IEnumerable介面實現GetEnumerator方法建立最簡單的迭代塊說明:迭代器返回值型別必須為IEnumerable(迭代類成員)和IEnumerator(迭代類)一個迭代器會出現一個或者多個yield語句,與一般語句塊的區別:yield return 一次返回迭代的下一個袁旭yield break 指出這個迭代的結束
```csharp
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections;            // 需要參照的名稱空間
namespace 實現迭代器常用的方法
{
    class Program
    {
        public static IEnumerable SimpleDemo()
        {
            yield return "string1";
            yield return "string2";
            yield return "string3";
            yield break;  //執行到此處就終止了迭代
            yield return "string4";
            yield return "string5";

        }
        //月份迭代
        public class Months : IEnumerable        //為了使用Foreach遍歷,要保證是可列舉型別的
        {
            string[] month = { "Jan", "Feb", "Mar", "Apr", "May", "June", "July", "Aug", "Nov", "Dec" };
            public IEnumerator GetEnumerator()
            {
                for(int i=0;i<month.Length;i++)
                {
                    yield return month[i];

                }
            }
        }
        static void Main(string[] args)
        {
            foreach (string item in SimpleDemo())
            {
                Console.WriteLine(item);
            }
            Months mon = new Months();
            foreach(string m in mon)
            {
                Console.WriteLine(m);
            }
            Console.ReadKey();

        }
    }
}

分佈類概述及其使用

分佈類定義:將類的定義拆分到兩個或多個資原始檔中。每個原始檔包含類定義的一部分,編譯應用程式時將把所有部分組合起來,這就是分佈類。

應用場合(partial):

  • 處理大型專案時,使一個類分佈於多個獨立檔案中,可以讓多位程式設計師同時對該類進行處理;
  • 使用自動生成的源時,無需重新建立原始檔便可將程式碼新增到類中。

vs在建立windows表單和web服務包裝程式碼等時都是用此方法。開發人員無須編譯vs所建立的檔案,即可建立使用這些類的程式碼。

實現過程:

  • 通過多個部分來定義一個類
  • partial關鍵字:必須直接放在class的前面
  • 分部類宣告的每個部分都必須包含partial修飾符,並且器宣告必須與其他部分位於同一名稱空間。
  • partial修飾符說明在其他位置可能還有同一個型別宣告的其他部分。但是這些其他部分並非必須存在:如果只有一個型別宣告,包含partial修飾符也是有效的。
  • 當分部類宣告指定了可存取性(藉助存取修飾符:public、protected、internal private)時,它必須與其他部分所指定的可存取性一致。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace _3_分部類
{
    //利用分部類實現階乘與冪指數運算
    partial class arithmetic    //階乘
    {
        public int factorial(int num)
        {
            int factorialval = 1;
            for(int i = num; i>0;i--)
            {
                factorialval *= i;
            }
            return factorialval;
        }
    }

    partial class arithmetic //冪指數運算
    {
        public int power(int num, int index)
        {
            int result = 1;
            for (int i = 0; i < index; i++)
            {
                result *= num;
            }

            return result; 
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            arithmetic a = new arithmetic();
            int num = 5;
            Console.WriteLine("呼叫分部類的第一部分——階乘計算結果:{0}", a.factorial(num));
            int index = 3;
            Console.WriteLine("呼叫分部類的第二部分——冪指函數計算結果:{0}", a.power(num, index));
            Console.ReadKey();
        }
    }
}

注意事項 :

  • 分部類時,同一個型別各個部分的所有分部類型別定義都必須使用partial進行修飾,必須具有相同的可存取性。
  • 同一個型別的各個部分的所有分部型別定義都必須在同一程式集合同一模組中進行定義。分部類定義不能跨越多個模組。
  • 使用partial關鍵字表明可在名稱空間內定義該類、結構或介面的其他部分,各個部分可以指定不同的基介面,最終型別將實現,所有分部宣告所列出的全部介面。

索引器概述及宣告

可以通過小標存取陣列中的元素的方式就是索引器
索引器允許類或結構的範例按照與陣列相同的方式進行索引。索引器的宣告和屬性的宣告非常相似,不同的是他們的存取器採用引數——索引器的宣告除了包括索引關鍵字(index)的宣告外,還包括this關鍵字。使得向陣列那樣對物件使用下標,並提供了通過索引方式方便第存取類的資料資訊的方法。(屬性的作用就是保護欄位,對欄位的取值和賦值進行限定)

  • 虛擬索引器:virtual
  • 外部索引器:extern 因為外部索引器宣告不提供任何實際的實現,所以他的每個存取器生摩納哥都由一個分號組成。
  • 抽象索引器:abstract 當要定義為抽象索引器時,必須提供空的get和set,必須在抽象類中宣告抽象索引器
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace _4_索引器概述及宣告
{
    //屬性宣告
    public class Clerk
    {
        private string name;   //欄位宣告,專供類內部使用,所以宣告為私有的
        public string Name     //屬性為外部事務,可以供其他類進行交流使用,所以宣告為公共的
        {
            get { return name; }
            set { name = value; }
        }
        private char gender;
        public char Gender
        {
            get
            {
                if (gender != '男' && gender != '女') gender = '男';
                return gender;
            }
            set
            {
                gender = value;
            }
        }

        //索引器宣告1
        //private int[] myint = new int[10];
        //public int this[int index]
        //{
        //    get { return myint[index]; }   //單獨存在為唯讀
        //    set { myint[index] = value; }  //單獨存在為只寫  ,兩個同時存在為讀寫
        //}


        //宣告一個虛擬的索引器
        //private int[] myint2 = new int[10];
        //public virtual int this[int index2]
        //{
        //    get { return myint2[index2]; }
        //    set { myint2[index2] = value; }
        //}

        // 宣告一個外部索引器
        public extern int this[int index]
        { get; set; }

    }
    // 抽象索引器宣告
    abstract class indexEaxmple
    {
        public abstract int this[int index]
        {
            get;
            set;
        }
    }
        class Program
        {
            static void Main(string[] args)
            {
            }
        }
    }

索引器在類中的使用

  • 索引器允許使用者按照處理陣列的方式索引類,存取時有兩種形式
  • 使用索引器可直接存取類範例:將陣列宣告為public成員並直接存取它的成員;

範例:1、存取類範例(容量為10的整型陣列為例)2、存取類成員(以星期演示)

using System;
namespace _5_索引器在類中的使用
{
    public class indexText //存取類的範例
    {
        private int[] array = new int[10];
        public int this[int index]
        {
            get
            {
                if (index < 0 || index > 10) return 0;
                else return array[index];
            }
            set
            {
                if (index >= 0 && index < 10) array[index] = value;
            }
        }
    }
    public class weekIndex //存取類成員
    {
        string[] week = { "星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期日" };
        private int getDay(string weekText)
        {
            int i = 0;
            foreach(string day in week)
            {
                if (day == weekText) return i+1;
                i++;
            }
            return -1;
        }
        public int this[string week]
        {
            get { return getDay(week); }

        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("存取類範例的結果");
            indexText Arr = new indexText();
            Arr[-5] = 5;
            Arr[0] = 15;
            Arr[2] = 60;
            Arr[11] = 65;
            Console.WriteLine("Arr[-5]={0}", Arr[-5]);
            Console.WriteLine("Arr[0]={0}", Arr[0]);
            Console.WriteLine("Arr[1]={0}", Arr[1]);
            Console.WriteLine("Arr[2]={0}", Arr[2]);
            Console.WriteLine("Arr[11]={0}", Arr[11]);
            Console.WriteLine("存取累成員結果");
            weekIndex we = new weekIndex();

            Console.WriteLine(we["星期三"]);
            Console.WriteLine(we["星期四"]);
            Console.WriteLine(we["星期八"]);
            Console.WriteLine(we["星期0"]);

            Console.ReadKey();
        }
    }
}

索引器在介面中的使用

索引器可以作為介面成員來宣告,單介面中的索引器宣告不包括任何存取修飾符,這是因為介面不包括任何程式設計程式語句,所以get和set存取器沒有程式主題,因此,存取索引器的用途是指示索引器時讀寫、唯讀還是隻寫

using System;
namespace _6_索引器在介面中的使用
{
    public interface iTextIndex
    {
        int this[int index]
        {
            get;
            set;
        }
    }
    class indexText:iTextIndex
    {
        // 演示容量為10的陣列,對範例成員的存取

        private int[] array = new int[10];
        public int this[int index]
        {
            get
            {
                if (index < 0 || index >= 10) return 0;
                else return array[index];
            }
            set
            {
                if (index > 0 && index < 10) array[index] = value;
            }
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            indexText Arr = new indexText();
            Arr[-1] = 5;
            Arr[4] = 10;
            Arr[9] = 20;
            Arr[14] = 30;
            for(int i=-1;i<15;i=i+5)
            {
                Console.WriteLine("Arr[{0}]={1}", i, Arr[i]);

            }
            Console.ReadKey();
        }
    }
}

小結及任務實施

索引器實現QQ狀態的存取,利用類成員進行存取,得出QQ狀態對應的索引值

using System;
namespace 本章小結及任務實施
{
    public class QQStateIndex
    {
        string [] qqState = { "線上", "離線", "忙碌", "Q我", "隱身" };
        private int getState(string stateText)
        {
            int i= 0;
            foreach(string stateString in qqState)
            {
                if (stateString == stateText) return i;
                i++;
            }
            return -1;
        }
        public int this[string stateString]
        {
            get { return getState(stateString); }

        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            QQStateIndex qs = new QQStateIndex();
            Console.WriteLine(qs["線上"]);
            Console.WriteLine(qs["忙碌"]);
            Console.WriteLine(qs["睡眠"]);
            Console.ReadKey();
        }
    }
}

到此這篇關於C# 迭代器分部類與索引器詳情的文章就介紹到這了,更多相關C# 迭代器,索引器內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com