Source: flickr/ Jeff Attaway
MVVM
The first M
stands for Model - an implementation of the application’s domain model that includes a data model along with business and validation logic. Examples of model objects include repositories, business objects, data transfer objects (DTOs), Plain Old CLR Objects (POCOs), and generated entity and proxy objects.
Immutability
In object-oriented and functional programming, an immutable object(unchangeable object) is an object whose state cannot be modified after it is created. This is in contrast to a mutable object (changeable object), which can be modified after it is created.
Why bother?
Imagine the next simple situation, your application downloads a JSON, deserialises it to an object and then presents the downloaded data. You would expect the downloaded data to be one-to-one to the data on the remote server, however the data can be accidentally or intentionally mutated.
Here is an example of a mutable Model
:
All the properties has public setters which means that any of those can be changed after the object creation. Even if we make all the setters private, it could be still possible to manipulate data within the List
.
Here is an example of immutable Model
:
There are no public setters available and mutable collection type is replaced by “immutable” one. There is no option to extend this class as well as changing the data after the object is created.
Note: IReadOnlyCollection is not a real immutable collection but an immutable facade. It is not thread safe and possible to cast to IList and try to manipulate the collection, however System.NotSupportedException will be thrown.
Alternatively we can add a System.Collections.Immutable
NuGet package and replace IReadOnlyCollection<T>
by IImmutableList<T>
if we want a real immutable collection.
JSON Deserialization
Often Models
used for deserialization and it can be tricky to deserialize JSON to immutable object. Luckily with Json.NET it is not an issue. We can easily serialize and deserialize MyImmutableObject
:
Please note that if your Model
has more than one constructor you will need to mark one for deserialization explicitly, by adding a JsonConstructor
attribute.
ORM
With .NET Standard we can use EntityFramework Core in our Xamarin.Forms applications which is great! And it is great twice since we can have a code first immutable model fully supported by EF.
Example:
When using an “immutable” Model
with EF keep in mind:
- Parameterless constructor - is required, should be private.
- Setters - are required, should private.
- Object tracking - should be disabled.
Notes:
- SQLite.NET did not work properly with private constructor and setters.
- We have to count with private setters since it is still possible to change a value with a private setter within the same class.
Conclusion
In this blogpost we discussed how to make immutable Models
and checked few common scenarios. I would recommend to start immutable and change to mutable if necessary. Here are few recommendations to keep in mind:
- Forget about private setters: prop -> propg
- Make publicly available properties readonly
- Use constructors
- Seal classes
- Use immutable collections or at least
[IReadOnlyCollection<T>](https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.ireadonlycollection-1?view=netstandard-2.0)
- The goal is not to get 100% immutability but to improve code quality
Immutability is a very interesting topic which has pros and cons. For example it may harm performance or introduce unnecessary complexity in some cases, so use it wisely. There are few great resources that I would recommend to get familiar with:
- Immutability in C# Part One: Kinds of Immutability by Eric Lippert
- .NET Framework - Immutable Collections by Hadi Brais
- The changing state of immutability C# by Jon Skeet (video)