Во многих случаях мне нравится делать типы неизменяемыми. Где это возможно, мне нравится делать их должным образом неизменяемыми, что означает полное исключение автоматически реализуемых свойств - в противном случае тип остается изменяемым внутри того же класса, что выглядит как ошибка, ожидающая возникновения.
«Правильная» неизменность будет включать в себя только чтение поля поддержки, что означает, что у вас есть , чтобы установить его в конструкторе ... обычно инициализируя его из другого параметра. Я нахожу довольно редким, что я могу лениво создавать экземпляр без дополнительной информации, как вы делаете в своем вопросе. Другими словами, это более распространенный шаблон для меня:
public class Person
{
private readonly string name;
public string Name { get { return name; } }
public Person(string name)
{
this.name = name;
}
}
Это становится громоздким, когда у вас много свойств - передача их всех в один конструктор может раздражать. Вот где вы хотели бы использовать шаблон компоновщика, с изменяемым типом, используемым для сбора данных инициализации, а затем конструктором, принимающим только компоновщик. Кроме того, именованные аргументы и необязательные параметры, доступные в C # 4, должны немного облегчить эту задачу.
Чтобы вернуться к вашей конкретной ситуации, я обычно пишу:
class Foo
{
private readonly MyObject myObject;
public SomeObject MyObject { get { return myObject; } }
public Foo()
{
myObject = new MyObject();
// logic
}
}
То есть, если строительство SomeObject
не является особенно дорогим. Это просто проще, чем делать это лениво в свойстве и, возможно, беспокоиться о проблемах с многопоточностью.
Теперь я предполагал, что неизменность является полезной целью здесь - но вы говорили о добавлении сеттера. Я не уверен, почему вы думаете, что это исключает использование поля, но это, безусловно, не так. Например, вы можете объединить ленивый экземпляр из вашего первого куска кода и иметь такой установщик:
class Foo
{
private SomeObject _myObject;
public SomeObject MyObject
{
get
{
if( _myObject == null )
{
_myObject = new SomeObject();
}
return _myObject;
}
set
{
// Do you want to only replace it if
// value is non-null? Or if _myObject is null?
// Whatever logic you want would go here
_myObject = value;
}
}
public Foo()
{
// logic
}
}
Я думаю, что основные решения должны быть:
- Хотите ли вы, чтобы тип был должным образом неизменным?
- Вам нужна ленивая инициализация?
- Вам нужна какая-то другая логика в ваших свойствах?
Если ответ на все эти вопросы отрицательный, используйте автоматически реализованное свойство. Если третий ответ меняется на «да», вы всегда можете преобразовать автоматически реализованное свойство в «нормальное» свойство позже.