5

重新認識 C# [2] - C# 2.0 Iterator 及其他進化

 1 year ago
source link: https://blog.darkthread.net/blog/cs-in-depth-notes-3/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

【本系列是我的 C# in Depth 第四版讀書筆記,背景故事在這裡

繼續談 C# 2.0

Iterator

  • foreach 在 IEnumerable 之外多支援 IEnumerable<T>,並加入了 Iterator
  • Iterator 可用於 IEnumerable、IEnumerable<T>、IEnumerator、IEnumerator<T>,Iterator Block 可使用 yield return 及 yield return 實現依序傳回資料,IEnumerable 傳回 object 型別,IEnumerable<T> 則為 T 型別
    註:這就是為什麼 foreach(var m in Regex.Matches(...)) 無法存取 m.Value 的原因,Matches 傳回的 MatchCollection 只有實作 IEnumerable,傳回型別為 object,需寫成 foreach (Match m in Regex.Matches(...)) 明確定義型別;如要結合 LINQ 則需 Cast 轉成 IEnumerable<Match>。參考:小技巧 - 對只支援 foreach 的集合執行 LINQ 動作
  • Lazy Execution、Lazy Evaluation
    跑迴圈時一次傳回一點,不必一次把全部結果算出來存進記憶體,效率好也省 RAM,延伸閱讀:善用 yield return 省時省 CPU 省 RAM,打造高效率程式
static IEnumerable<int> CreateSimpleIterator()
{ // 以下區域為 Interator Block,GetEnumerator() 時不會馬上執行
    yield return 10; //直到第一次 MoveNext() 才會執行這行
    for (int i = 0; i < 3; i++)
    {
        yield return i; // 之後每次 MoveNext() 執行這裡
    }
    yield return 20;
}

IEnumerable<int> enumerable = CreateSimpleIterator();
using (IEnumerator<int> enumerator =
    enumerable.GetEnumerator())
{
    while (enumerator.MoveNext())
    {
        int value = enumerator.Current;
        Console.WriteLine(value);
    }
}
  • 在 Iterator Block 放 finally 會怎樣?
static IEnumerable<string> Iterator()
{
    try
    {
        Console.WriteLine("Before first yield");
        yield return "first"; //想像成 yield return 後暫停在這裡
        Console.WriteLine("Between yields");
        yield return "second"; //yield return 後暫停在這裡
        Console.WriteLine("After second yield");
    }
    finally
    {
        // 結束 foreach 時才執行這裡
        Console.WriteLine("In finally block");
    }
}
  • Iterator Block 如果有用到 Unmanaged 資源(例如:讀取檔案),記得用 using 隱含強制呼叫 IDispose,foreach 呼叫過程即使出錯也要釋放資源。
  • Iterator Block 在編譯時會被轉成一個實作狀態機 Pattern 的類別,有點小複雜,有興趣請看書或參考安德魯這篇:How yield return Work ?

C# 2.0 的其他小改進

  • Partial Types
    將同一類別、Struct、介面的部分寫在多個 .cs,很常搭配程式產生器使用,在程式自動產生 .cs 外再新增一個個 .cs 寫自訂邏輯。
  • Static Class
    強制類別不能建立 Instance,搭配 C# 3.0 的擴充方法使用
  • Property 的 set/get 可以設不同存取等級
private string _text;
public string Test { 
    get { return _text; } 
    private set { _text = value; } 
}
  • Namespace 別名
using WinForms = System.Windows.Forms;
using WebForms = System.Web.UI.WebControls;
//另外 WinForms.Button 可以寫成 WinForms::Button,防止有類別叫 WinForms
//global::System.DateTime 常用於程式碼產生器避免撞名
  • External Alias 來自不同組件的同 Namespace 同名型別
extern alias JsonNet;
extern alias JsonNetAlternative;

using JsonNet::Newtonsoft.Json.Linq;
using AltJObject = JsonNetAlternative::Newtonsoft.Json.Linq.JObject;
...
JObject obj = new JObject();
AltJObject alt = new AltJObject();
  • Pragma Directive
#pragma warning disable CS0219 //停用 variable is assigned but its value is never used 警告
int variable = CallSomeMethod();
#pragma warning restore CS0219
  • Fixed-Size Buffer (適用 Unsafe 程式,跟 C/C++ 世界溝通可用)
unsafe struct VersionedData
{
    public int Major;
    public int Minor;
    public fixed byte Data[16];
}

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK