麻豆小视频在线观看_中文黄色一级片_久久久成人精品_成片免费观看视频大全_午夜精品久久久久久久99热浪潮_成人一区二区三区四区

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

Immutable(不可變)集合

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

不可變集合,顧名思義就是說集合是不可被修改的。集合的數據項是在創建的時候提供,并且在整個生命周期中都不可改變。

為什么要用immutable對象?immutable對象有以下的優點:

  1. 對不可靠的客戶代碼庫來說,它使用安全,可以在未受信任的類庫中安全的使用這些對象
  2. 線程安全的:immutable對象在多線程下安全,沒有競態條件
  3. 不需要支持可變性, 可以盡量節省空間和時間的開銷. 所有的不可變集合實現都比可變集合更加有效的利用內存 (analysis)
  4. 可以被使用為一個常量,并且期望在未來也是保持不變的

immutable對象可以很自然地用作常量,因為它們天生就是不可變的對于immutable對象的運用來說,它是一個很好的防御編程(defensive PRogramming)的技術實踐。

微軟.NET團隊已經正式發布了不可變集合,可以通過Nuget添加,包括了下面的不可變集合:

System.Collections.Immutable.ImmutableArray

System.Collections.Immutable.ImmutableArray<T>

System.Collections.Immutable.ImmutableDictionary

System.Collections.Immutable.ImmutableDictionary<TKey,TValue>

System.Collections.Immutable.ImmutableHashSet

System.Collections.Immutable.ImmutableHashSet<T>

System.Collections.Immutable.ImmutableList

System.Collections.Immutable.ImmutableList<T>

System.Collections.Immutable.ImmutableQueue

System.Collections.Immutable.ImmutableQueue<T>

System.Collections.Immutable.ImmutableSortedDictionary

System.Collections.Immutable.ImmutableSortedDictionary<TKey,TValue>

System.Collections.Immutable.ImmutableSortedSet

System.Collections.Immutable.ImmutableSortedSet<T>

System.Collections.Immutable.ImmutableStack

System.Collections.Immutable.ImmutableStack<T>

MSDN的文檔參考 https://msdn.microsoft.com/zh-cn/library/system.collections.immutable.aspx ,怎么使用呢?我們來看一個例子,假設你已經建立了一個計費系統,你需要一個不可變的設計,在多線程操作的情況下不需要擔心數據損壞。例如,你需要通過一個輔助線程打印數據的一個快照,這種方式避免阻塞用戶的編輯操作,允許用戶繼續編輯而不影響打印。

可變的數據模型是這樣:

class Order
{
    public Order()
    {
        Lines = new List<OrderLine>();
    }

    public List<OrderLine> Lines { get; private set; }
}

class OrderLine
{
    public int Quantity { get; set; }
    public decimal UnitPrice { get; set; }
    public float Discount { get; set; }

    public decimal Total
    {
        get
        {
         return Quantity * UnitPrice * (decimal) (1.0f - Discount);
        }
    }
}

下面我們把它轉換為不可變的設計:

class OrderLine
{
    public OrderLine(int quantity, decimal unitPrice, float discount)
    {
        Quantity = quantity;
        UnitPrice = unitPrice;
        Discount = discount;
    }

    public int Quantity { get; private set; }

    public decimal UnitPrice { get; private set; }

    public float Discount { get; private set; }

    public decimal Total
    {
        get
        {
         return Quantity * UnitPrice * (decimal) (1.0f - Discount);
        }
    }
}

這種新設計要求您創建一個訂單,每當任何屬性值變化創建一個新實例。您可以通過添加 WithXxx 方法,使您可以更新單個屬性而無需顯式調用構造函數:

class OrderLine
{
    // ...

    public OrderLine WithQuantity(int value)
    {
        return value == Quantity
                ? this
                : new OrderLine(value, UnitPrice, Discount);
    }

    public OrderLine WithUnitPrice(decimal value)
    {
        return value == UnitPrice
                ? this
                : new OrderLine(Quantity, value, Discount);
    }

    public OrderLine WithDiscount(float value)
    {
        return value == Discount
                ? this
                : new OrderLine(Quantity, UnitPrice, value);
    }
}

這使得不可變使用起來比較簡單:

OrderLine apple = new OrderLine(quantity: 1, unitPrice: 2.5m, discount: 0.0f);

OrderLine discountedAppled = apple.WithDiscount(.3f);

現在讓我們看看我們如何落實訂單的不變性。Lines 屬性已經是只讀的但它指的是可變對象。因為它是一個集合,它可以容易地通過簡單地將它替換 ImmutableList <T>轉換:

class Order
{
    public Order(IEnumerable<OrderLine> lines)
    {
        Lines = lines.ToImmutableList();
    }

    public ImmutableList<OrderLine> Lines { get; private set; }

    public Order WithLines(IEnumerable<OrderLine> value)
    {
        return Object.ReferenceEquals(Lines, value)
            ? this
            : new Order(value);
    }
}

這種設計有一些有趣的屬性:

• 該構造函數接受 IEnumerable <T>,允許傳遞任何集合中。

• 我們使用 ToImmutableList() 擴展方法,將轉換為 ImmutableList <OrderLine>。如果該實例已經是不可變的列表,它會簡單地轉換而不是創建一個新的集合。

• 該 WithLines() 方法遵循 我們的訂單公約,如果新的列表和當前列表是相同的就可以避免創建一個新的實例。

我們還可以加一些便利的方法來使它更易于更新訂單行:

class Order
{
    //...

    public Order AddLine(OrderLine value)
    {
        return WithLines(Lines.Add(value));
    }

    public Order RemoveLine(OrderLine value)
    {
        return WithLines(Lines.Remove(value));
    }

    public Order ReplaceLine(OrderLine oldValue, OrderLine newValue)
    {
        return oldValue == newValue
                ? this
                : WithLines(Lines.Replace(oldValue, newValue));
    }
}

增補訂單的代碼看起來是這樣子:

OrderLine apple = new OrderLine(quantity: 1, unitPrice: 2.5m, discount: 0.0f);
Order order = new Order(ImmutableList.Create(apple));

OrderLine discountedApple = apple.WithDiscount(discount);
Order discountedOrder = order.ReplaceLine(apple, discountedApple);

這種設計的好處是,它盡可能避免了不必要的對象創建。例如,當折扣的值等于 0.0 f,即時沒有折扣,,discountedApple 和 discountedOrder 引用現有實例的蘋果和訂單。

這是因為:

1.apple.WithDiscount() 將返回蘋果的現有實例,因為新的折扣是相同折扣屬性的當前值。

2.order.ReplaceLine() 如果兩個參數都相同,將返回現有實例。

我們不變的集合其他操作遵循這種最大化重用。例如,將訂單行添加到 1000 的訂單行的訂單與 1,001 訂單行不會創建整個的新列表。相反,它將重用現有列表一大塊。這是可能的因為列表內部結構是為一棵樹,允許共享不同實例的節點。

這里有兩個視頻介紹可變性集合:

 Immutable Collections for .NET

 Inner workings of immutable collections

不可變集合的系列博客推薦:

Exploring the .NET CoreFX Part 9: Immutable Collections and the Builder 

Exploring the .NET CoreFX Part 13: ImmutableList is an AVL Tree

Exploring the .NET CoreFX Part 14: Inside Immutable Collections


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 99久久精品免费 | 亚州综合| 午夜国产精品成人 | 国产999在线 | 精品久久久91| 国产91久久久 | 日韩欧美激情视频 | 国产精品剧情一区二区在线观看 | 国产噜噜噜噜噜久久久久久久久 | 最新中文字幕日本 | 性 毛片 | 特级a欧美做爰片毛片 | 亚洲精品午夜视频 | 一级做受大片免费视频 | 夜夜看| 久久久久久久久久久久久久久伊免 | av在线播放免费 | 热99精品视频 | 一级电影在线免费观看 | 欧美在线观看黄色 | 欧美激情第一区 | 97zyz成人免费视频 | 一级爱片 | 免费观看三级毛片 | 天海翼四虎精品正在播放 | 欧产日产国产精品99 | 欧产日产国产精品乱噜噜 | 一级做a爱片性色毛片 | 天天干天天碰 | caoporn国产一区二区 | 国产一区二区三区高清 | 亚洲一级片免费观看 | 成人在线视频在线观看 | 欧美亚洲国产成人 | 一级电影免费在线观看 | 欧美成人区 | 午夜视频中文字幕 | 国产噜噜噜噜噜久久久久久久久 | 九九色在线观看 | 国产精品毛片va一区二区三区 | 销魂美女一区二区 |