No puede utilizar inicializadores de objetos con objetos inmutables. Requieren propiedades configurables.
Un objeto inmutable implica "no cambia después de la creación". Hacer Name
un parámetro constructor expresa claramente ese principio.
Si el objeto se vuelve demasiado complicado para un constructor comprensible, también se puede utilizar el Builder. En general, el propio constructor tendrá propiedades mutables (que puede usar en los inicializadores de objetos), y su método .Build() creará la instancia real.
EDIT (OP): Voy a agregar mi propio ejemplo de un generador que cociné aquí, luego acepto esta respuesta ya que propone una solución razonable.
class MyObject
{
public class Builder
{
public Builder()
{
// set default values
Name = String.Empty;
}
public MyObject Build()
{
return new MyObject(Name);
}
public string Name { get; set; }
}
private static int nextId;
protected MyObject(string name)
{
Id = ++nextId;
Name = name;
}
public int Id { get; private set; }
public string Name { get; private set; }
}
entonces usted puede construir una instancia de ella con lo siguiente:
MyObject test = new MyObject.Builder { Name = "foo" }.Build();
EDITAR: Esta es mi opinión sobre el patrón:
public abstract class Builder<T>
{
public static implicit operator T(Builder<T> builder)
{
return builder.Build();
}
private bool _built;
public T Build()
{
if(_built)
{
throw new InvalidOperationException("Instance already built");
}
_built = true;
return GetInstance();
}
protected abstract T GetInstance();
}
Aquí está su ejemplo, como implementado con Builder<T>
. Se aprovecha de las reglas de alcance de tipos anidados para acceder a la incubadora privada:
public class MyObject
{
private static int nextId;
protected MyObject()
{
Id = ++nextId;
}
public int Id { get; private set; }
public string Name { get; private set; }
public sealed class Builder : Builder<MyObject>
{
private MyObject _instance = new MyObject();
protected override MyObject GetInstance()
{
// Validate properties here
return _instance;
}
public string Name
{
get { return _instance.Name; }
set { _instance.Name = value; }
}
}
}
Tiene una conversión implícita al tipo de destino, lo que le permite hacer esto:
MyObject myObject = new MyObject.Builder { Name = "Some name" };
O esto:
public void Foo(MyObject myObject)
// ...
Foo(new MyObject.Builder { Name = "Some name" });
He actualizado mi respuesta para incluir mi versión del patrón del generador. Espero eso ayude. –