Почему required свойствам не разрешается иметь модификатор set или init, который более ограничивает, чем модификатор класса, содержащего эти свойства?

Как достичь требуемой логики, чтобы внутри сборки проперти было обязательно инициализировано при создании объекта, и при этом объект нельзя было создать вне сборки, но можно было прочитать его поля? Почему не удается объявить свойство в указанном примере? В чем ошибка?
  • 16 февраля 2024 г. 11:18
Ответы на вопрос 2
required свойствам не разрешается иметь модификатор set или init, который более ограничивает, чем модификатор класса, содержащего эти свойства, потому что это может нарушить принципы инкапсуляции и создать непредсказуемое поведение.

Например, если модификатор класса указывает, что свойство может быть прочитано и изменено только внутри сборки, а модификатор set или init для этого свойства указывает, что оно может быть изменено только внутри класса, то это приведет к противоречию. В конечном итоге свойство станет доступным только для чтения извне, но никогда не сможет быть изменено. Это может вызвать путаницу и привести к нерабочему коду.

В примере, который представлен, пытается объявиться свойство required с модификатором init, который ограничивает его доступность только для инициализации внутри сборки. Однако, это невозможно, потому что с модификатором required свойства обязательно должно быть возможно изменение значения свойства после его инициализации.

Для достижения требуемой логики, чтобы внутри сборки проперти было обязательно инициализировано при создании объекта, и при этом объект нельзя было создать вне сборки, но можно было прочитать его поля, можно использовать следующий подход:

1. Установить модификатор set.accessibility внутри геттера, чтобы сделать его доступным только внутри сборки.
2. Установить модификатор init.accessibility внутри инициализатора, чтобы сделать его доступным только внутри сборки.
3. Определить приватное свойство, которое будет хранить значение и будет доступно только внутри класса.

Пример:

```swift
public class MyClass {
    private var _myProperty: String
    
    public var myProperty: String {
        get {
            return _myProperty
        }
        set {
            _myProperty = newValue
        }
    }
    
    public required init(myProperty: String) {
        self._myProperty = myProperty
    }
}
```

В этом примере свойство `_myProperty` объявлено как приватное, чтобы оно было доступно только внутри класса. Оболочка `myProperty` предоставляет доступ к этому приватному свойству и определяет модификатор set.accessibility, чтобы его можно было изменять только внутри сборки. Инициализатор `required init` также имеет модификатор init.accessibility, чтобы он был доступен только внутри сборки. Таким образом, внутри сборки свойство `myProperty` может быть обязательно инициализировано при создании объекта, а объект нельзя создать вне сборки. В то же время, свойство `myProperty` может быть прочитано извне класса.
Представь ситуацию, что кто-то во внешней сборке создает твой класс и ему обязательно нужно будет инициализировать это поле - он не сможет, т.к. internal set . А сделать это просто - рефлексия: 
SomeClass obj = (SomeClass) typeof(SomeClass).GetConstructor(
                  BindingFlags.NonPublic | BindingFlags.Instance,
                  null, Type.EmptyTypes, null).Invoke(null);

И все!

Тут несколько решений:
1. Объяви класс как internal
2. Выдели интерфейс с публичным get без set
3. Для хранения используй поле и доступ к нему через свойство (но тут уже и required не особо нужен)
Похожие вопросы