如何使用 C# 中的 Lazy

wyfem發表於2021-09-09

延遲初始化 是一種將物件的建立延遲到第一次需要用時的技術,換句話說,物件的初始化是發生在真正需要的時候才執行,值得注意的是,術語 延遲初始化延遲例項化 的意思是相同的——可以互換使用,透過使用 延遲初始化 技術,可以避免應用程式不必要的計算和記憶體消耗,這篇文章我們將會討論如何在 C# 中使用 延遲初始化。

有些朋友聽完這些可能會懵逼,接下來用一個簡單的例子來了解下 延遲載入 的場景,考慮下面兩個類, CustomerOrder, Customer 類包含了一個 Orders 屬性,一個人肯定會有很多的訂單,也就意味著它可能包含了很多的資料,甚至還需要連線資料庫去獲取 Orders 記錄,在這種場景下,沒必要給 customer 集合中的所有人都帶上完整的 orders,這個初始化開銷是巨大的,最佳化點就是不載入 Orders,直到某些 customer 真的需要 Orders 時才按需灌入。

使用 Lazy

你可以自己寫一段邏輯來實現 延遲初始化,在 .Net Framework 4.0 之後就沒必要了, 因為在 System 名稱空間下已經提供了 Lazy,而且還是 執行緒安全 的,可以使用這個類來延遲 資源密集型 的物件按需建立。

當使用 Lazy 的時候,這裡的 T 就是你要延遲的集合,那如何做到按需載入呢?呼叫 Lazy.Value 即可,下面的程式碼片段展示瞭如何使用 Lazy


Lazy> orders = new Lazy>();
IEnumerable result = lazyOrders.Value;

現在,考慮下面的兩個類: AuthorBlog,一個作者可以寫很多文章,所以這兩個類之間是 一對多 的關係,下面的程式碼片段展示了這種關係。


    public class Author
    {
        public int Id { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string Address { get; set; }
        public List Blogs { get; set; }
    }
    public class Blog
    {
        public int Id { get; set; }
        public string Title { get; set; }
        public DateTime PublicationDate { get; set; }
    }

值得注意的是,關係型資料庫中的 一對多 關係對映到物件模型就是 Author 類中增加一個 List Blogs 屬性,使用這個屬性,Author 就可以維持一個或者多個 Blog 例項物件,對吧。

現在假定在 使用者介面 上僅需展示 Author 的基礎資訊,比如說:(firstname,lastname,address),在這種場景下,給 Author 物件載入 Blogs 集合是毫無意義的,當真的需要載入 Blogs 時,執行 Blogs.Value 即可立即執行,下面展示了 Lazy Blogs 的用法。


    public class Author
    {
        public int Id { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string Address { get; set; }
        public Lazy> Blogs => new Lazy>(() => GetBlogDetailsForAuthor(this.Id));
        private IList GetBlogDetailsForAuthor(int Id)
        {
       //Write code here to retrieve all blog details for an author.
        }
    }

使用通用的 Lazy

接下來讓我們看看如何使用泛型的 Lazy 實現單例模式,下面的 StateManager 是執行緒安全的,同時為了演示 延遲初始化,我使用了 靜態建構函式 來確保 C# 編譯器不會將它標記為 beforefieldinit


    public sealed class StateManager
    {
        private StateManager()
        {
        }

        public static StateManager Instance
        {
            get
            {
                return Nested.obj;
            }
        }
        private class Nested
        {
            static Nested()
            {
            }
            internal static readonly StateManager obj = new StateManager();
        }
    }

下面我用 Lazy 來包裝 StateManager,你會發現使用 Lazy 來做延遲初始化真的是太簡單了。。。


    public class StateManager
    {
        private static readonly Lazy obj = new Lazy(() => new StateManager());
        private StateManager() { }
        public static StateManager Instance
        {
            get
            {
                return obj.Value;
            }
        }
    }

可以瞄一下上面程式碼的 Instance 屬性,它被做成只讀屬性了,同時也要注意 obj.Value 也是一個只讀屬性。


    public class Lazy
    {
        public T Value
        {
            get
            {
                if (_state != null)
                {
                    return CreateValue();
                }
                return _value;
            }
        }
    }

延遲初始化 是一個很不錯的效能最佳化技術,它允許你將那些 資源密集型 的物件延遲到你真正需要載入的時候再載入,大家結合自己的場景盡情的使用吧!

更多高質量乾貨:參見我的 GitHub: [csharptranslate] github.com/ctripxchuang/csharptranslate

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/2894/viewspace-2826894/,如需轉載,請註明出處,否則將追究法律責任。

相關文章