【本系列是我的 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];
}

My notes for C# in Depth part 3


Comments

Be the first to post a comment

Post a comment


39 - 20 =