Immutable (immutable) set and Immutable set

Source: Internet
Author: User

Immutable (immutable) set and Immutable set

Immutable set, as the name implies, means that the set cannot be modified. The data items of a set are provided during creation and cannot be changed throughout the lifecycle.

Why use an immutable object? The immutable object has the following advantages:

Immutable objects can be used as constants naturally, because they are inherently immutable. For the use of immutable objects, they are a good technical practice of Defense programming (defensive programming.

The Microsoft. NET team has officially released the immutable set, which can be added through Nuget, including the following immutable set:

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 Documentation Reference https://msdn.microsoft.com/zh-cn/library/system.collections.immutable.aspx, how to use it? Let's look at an example. Suppose you have already created a billing system, and you need an immutable design. In the case of multi-threaded operations, you do not need to worry about data corruption. For example, you need to print a snapshot of data through an auxiliary thread. This method avoids blocking the user's editing operations and allows the user to continue editing without affecting printing.

The variable data model is as follows:

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 );
}
}
}

Next we will convert it into an immutable design:

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 );
}
}
}

This new design requires you to create an order and create a new instance whenever any attribute value changes. You can add the WithXxx method so that you can update a single attribute without explicitly calling the constructor:

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 );
}
}

This makes it easier to use immutable:

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

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

Now let's take a look at how we implement the immutability of orders. The Lines attribute is read-only, but it refers to a mutable object. Because it is a set, it can be easily converted by simply replacing 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 );
}
}

This design has some interesting attributes:

• This constructor accepts IEnumerable <T> and allows passing in any collection.

• We use the ToImmutableList () Extension Method to convert it to ImmutableList <OrderLine>. If the instance is already an unchangeable list, it will simply convert it instead of creating a new set.

• The WithLines () method complies with our order conventions. If the new list is the same as the current list, you can avoid creating a new instance.

We can also add some convenient methods to make it easier to update the order line:

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 ));
}
}

The code for adding an order looks like this:

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

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

The benefit of this design is that it avoids unnecessary object creation as much as possible. For example, if the discount value is equal to 0.0 f, there is no immediate discount. discountedApple and discountedOrder reference the existing instance's apple and orders.

This is because:

1. apple. WithDiscount () will return the existing instance of apple, because the new discount is the current value of the same discount attribute.

2. order. ReplaceLine () if both parameters are the same, an existing instance is returned.

Other operations in our unchanged set follow this principle to maximize reuse. For example, adding an order line to an order line of 1000 and an order line of 1,001 do not create an entire new list. Instead, it will reuse a large part of the existing list. This is possible because the internal structure of the list is a tree that allows nodes of different instances to be shared.

There are two sets of videos that describe variability:

Immutable Collections for. NET

Inner workings of immutable collections

Recommended series of blogs with immutable collections:

Indexing ing the. NET CoreFX Part 9: Immutable Collections and the Builder

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

Indexing ing the. NET CoreFX Part 14: Inside Immutable Collections

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.