Question

I'm learning about DDD, and have come across the statement that "value-objects" should be immutable. I understand that this means that the objects state should not change after it has been created. This is kind of a new way of thinking for me, but it makes sense in many cases.

Ok, so I start creating immutable value-objects.

  • I make sure they take the entire state as parameters to the constructor,
  • I don't add property setters,
  • and make sure no methods are allowed to modify the content (only return new instances).

But now I want to create this value object that will contain 8 different numeric values. If I create a constructor having 8 numeric parameters I feel that it will not be very easy to use, or rather - it will be easy to make a mistake when passing in the numbers. This can't be good design.

So the questions is: Are there any other ways of making my immutable object better.., any magic that can be done in C# to overcome a long parameter list in the constructor? I'm very interested in hearing your ideas..

UPDATE: Before anyone mentions it, one idea has been discussed here: Immutable object pattern in C# - what do you think?

Would be interested in hearing other suggestions or comments though.

Was it helpful?

Solution

Use a builder:

public class Entity
{
   public class Builder
   {
     private int _field1;
     private int _field2;
     private int _field3;

     public Builder WithField1(int value) { _field1 = value; return this; }
     public Builder WithField2(int value) { _field2 = value; return this; }
     public Builder WithField3(int value) { _field3 = value; return this; }

     public Entity Build() { return new Entity(_field1, _field2, _field3); }
   }

   private int _field1;
   private int _field2;
   private int _field3;

   private Entity(int field1, int field2, int field3) 
   {
     // Set the fields.
   }

   public int Field1 { get { return _field1; } }
   public int Field2 { get { return _field2; } }
   public int Field3 { get { return _field3; } }

   public static Builder Build() { return new Builder(); }
}

Then create it like:

Entity myEntity = Entity.Build()
                   .WithField1(123)
                   .WithField2(456)
                   .WithField3(789)
                  .Build()

If some of the parameters are optional you won't need to call the WithXXX method and they can have default values.

OTHER TIPS

At the moment, you'd have to use a constructor with lots of args, or a builder. In C# 4.0 (VS2010), you can use named/optional arguments to achieve something similar to C# 3.0 object-initializers - see here. The example on the blog is:

  Person p = new Person ( forename: "Fred", surname: "Flintstone" );

But you can easily see how something similar can apply for any constructor (or other complex method). Compare to the C# 3.0 object-initializer syntax (with a mutable type):

 Person p = new Person { Forename = "Fred", Surname = "Flintstone" };

Not much to tell them apart, really.

Jon Skeet has posted some thoughts on this subject too, here.

Off the top of my head, two different answers come to mind ...

... the first, and probably simplest, is to use an object factory (or builder) as a helper that ensures you get things right.

Object initialization would look like this:

var factory = new ObjectFactory();
factory.Fimble = 32;
factory.Flummix = "Nearly";
var mine = factory.CreateInstance();

... the second is to create your object as a conventional, mutable, object with a Lock() or Freeze() function. All of your mutators should check to see if the object has been locked, and throw an exception if it has.

Object initialization would look like this:

var mine = new myImmutableObject();
mine.Fimble = 32;
mine.Flummix = "Nearly";
mine.Lock(); // Now it's immutable.

Which method to take depends a lot on your context - a factory has the advantage of being convenient if you have a series of similar objects to construct, but it does introduce another class to write and maintain. A lockable object means there is only one class, but other users might get unexpected runtime errors, and testing is harder.

Although it is probably part of the domain of what you are doing, and thus my suggestion may be invalid, what about attempting to break down the 8 parameters into logical groups?

Whenever I see heaps of parameters, i feel like the object/method/contructor ought to be simpler.

I have been boggled with the same question as complex constructors is also bad design to me. I am also not a big fan of the builder concept as it seems like too much extra code to maintain. What we need is popsicle immutability, which means that an object starts out as mutable where you are allowed to use the property setters. When all properties are set there must be a way of freezing the object into an immutable state. This strategy is unfortunately not supported natively in the C# language. I therefore ended up designing my own pattern for creating immutable objects as described in this question:

Immutable object pattern in C# - what do you think?

Anders Hejlsberg is talking about support for this type of immutability from 36:30 in the following interview:

Expert to Expert: Anders Hejlsberg - The Future of C#

You can use reflection in order to initialize all the fields of the object and laziness to make "setter" like methods (using monadic functional style) in order to chain the set methods/functions together.

For example:

You can use this base class:

public class ImmutableObject<T>
{
    private readonly Func<IEnumerable<KeyValuePair<string, object>>> initContainer;

    protected ImmutableObject() {}

    protected ImmutableObject(IEnumerable<KeyValuePair<string,object>> properties)
    {
        var fields = GetType().GetFields().Where(f=> f.IsPublic);

        var fieldsAndValues =
            from fieldInfo in fields
            join keyValuePair in properties on fieldInfo.Name.ToLower() equals keyValuePair.Key.ToLower()
            select new  {fieldInfo, keyValuePair.Value};

        fieldsAndValues.ToList().ForEach(fv=> fv.fieldInfo.SetValue(this,fv.Value));

    }

    protected ImmutableObject(Func<IEnumerable<KeyValuePair<string,object>>> init)
    {
        initContainer = init;
    }

    protected T setProperty(string propertyName, object propertyValue, bool lazy = true)
    {

        Func<IEnumerable<KeyValuePair<string, object>>> mergeFunc = delegate
                                                                        {
                                                                            var propertyDict = initContainer == null ? ObjectToDictonary () : initContainer();
                                                                            return propertyDict.Select(p => p.Key == propertyName? new KeyValuePair<string, object>(propertyName, propertyValue) : p).ToList();
                                                                        };

        var containerConstructor = typeof(T).GetConstructors()
            .First( ce => ce.GetParameters().Count() == 1 && ce.GetParameters()[0].ParameterType.Name == "Func`1");

        return (T) (lazy ?  containerConstructor.Invoke(new[] {mergeFunc}) :  DictonaryToObject<T>(mergeFunc()));
    }

    private IEnumerable<KeyValuePair<string,object>> ObjectToDictonary()
    {
        var fields = GetType().GetFields().Where(f=> f.IsPublic);
        return fields.Select(f=> new KeyValuePair<string,object>(f.Name, f.GetValue(this))).ToList();
    }

    private static object DictonaryToObject<T>(IEnumerable<KeyValuePair<string,object>> objectProperties)
    {
        var mainConstructor = typeof (T).GetConstructors()
            .First(c => c.GetParameters().Count()== 1 && c.GetParameters().Any(p => p.ParameterType.Name == "IEnumerable`1") );
        return mainConstructor.Invoke(new[]{objectProperties});
    }

    public T ToObject()
    {
        var properties = initContainer == null ? ObjectToDictonary() : initContainer();
        return (T) DictonaryToObject<T>(properties);
    }
}

Can be implemented like so:

public class State:ImmutableObject<State>
{
    public State(){}
    public State(IEnumerable<KeyValuePair<string,object>> properties):base(properties) {}
    public State(Func<IEnumerable<KeyValuePair<string, object>>> func):base(func) {}

    public readonly int SomeInt;
    public State someInt(int someInt)
    {
        return setProperty("SomeInt", someInt);
    }

    public readonly string SomeString;
    public State someString(string someString)
    {
        return setProperty("SomeString", someString);
    }
}

and can be used like this:

//creating new empty object
var state = new State();

// Set fields, will return an empty object with the "chained methods".
var s2 = state.someInt(3).someString("a string");
// Resolves all the "chained methods" and initialize the object setting all the fields by reflection.
var s3 = s2.ToObject();
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top