Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

is it possible to create immutable object without passing everything in constructor?

Tags:

c#

I want to make my class immutable. Obvious way would be to declare all fields as get; private set; and to initialize all fields in constructor. So clients must provide everything in constructor. The problem is that when there are ~10 or more fields passing them in constructor become very unreadable, because there are no labels for each field.

For example this is pretty readable:

info = new StockInfo
        {
            Name = data[0] as string,
            Status = s,
            LotSize = (int)data[1],
            ISIN = data[2] as string,
            MinStep = (decimal)data[3]
        };

compare to this:

new StockInfo(data[0] as string, s, (int) data[1], data[2] as string, (decimal) data[3])

And now imaging that I have 10 or more parameters.

So how can I make class immutable saving readability?

I can suggest only use the same formatting when using constructor:

info = new StockInfo(
            data[0] as string,           // Name
            s,                           // Status
            (int)data[1],                // LotSize
            data[2] as string,           // ISIN
            (decimal)data[3]             // MinStep
       );

Can you suggest something better?

like image 706
Oleg Vazhnev Avatar asked Aug 14 '12 15:08

Oleg Vazhnev


People also ask

What is required to create an immutable object in Java?

To create an immutable class in Java, you have to do the following steps. Declare the class as final so it can't be extended. Make all fields private so that direct access is not allowed. Don't provide setter methods for variables.

Can we create an immutable object which contains a mutable object?

If you want to encapsulate a mutable object into an immutable one, then you need to: Create a copy of the mutable object (i.e. via copy constructor, cloning, serialization/deserialization, etc.); never store the reference to the original mutable object. Never return the mutable object.

Do all properties of immutable objects need to be final?

No, it is not mandatory to have all properties final to create an immutable object. In immutable objects you should not allow users to modify the variables of the class. You can do this just by making variables private and not providing setter methods to modify them.


2 Answers

Here is how you could do it, using C#'s named parameters:

var info = new StockInfo
(
    Name: data[0] as string,
    Status: s,
    LotSize: (int)data[1],
    ISIN: data[2] as string,
    MinStep: (decimal)data[3]
);
like image 61
Adam Avatar answered Oct 15 '22 06:10

Adam


Here are some options. You will have to decide what's best for you:

Use a classic immutable object (with a massive constructor) with named arguments for readability. (Drawbacks: Some frown on having many constructor arguments. May be inconvenient to use from other .NET languages without support for named arguments.)

info = new StockInfo
           (
             name: data[0] as string,
             status: s,
             ...
           )

Expose the mutable object through an immutable interface. (Drawbacks: The object could still be mutated with casting. Extra type to write.)

public interface IStockInfo
{
   string Name { get; }
   string Status { get; }
}

IStockInfo info = new StockInfo
                      {
                          Name = data[0] as string,
                          Status = s,
                          ...
                      }

Expose a read-only view of the mutable object - see ReadOnlyCollection<T> for example. (Drawbacks: Extra type to implement. Extra object created. Extra indirections.)

var readOnlyInfo = new ReadOnlyStockInfoDecorator(info);

Expose an immutable clone of the mutable object. (Drawbacks: Extra type to implement. Extra object created. Copying required.)

var immutableInfo = new ImmutableStockInfo(info);

Use freezable objects. (Drawback: Post-freeze mutation-attempts won't be caught until execution-time.)

info.Freeze();
info.Name = "Test"; // Make this throw an exception.

Use fluent-style builders or similar (Drawbacks: Some may be unfamiliar with the pattern. Lots of extra code to write. Lots of copies created. Intermediate states may possibly be illegal)

info = StockInfo.FromName(data[0] as string)
                .WithStatus(s) // Make this create a modified copy
                .WithXXX() ;
like image 44
Ani Avatar answered Oct 15 '22 05:10

Ani