Подтвердить что ты не робот

Как я могу сделать версию класса только для чтения?

У меня есть класс с различными общедоступными свойствами, который я разрешаю пользователям редактировать через сетку свойств. Для сохранения этот класс также сериализуется/десериализуется в/из файла XML через DataContractSerializer.

Иногда я хочу, чтобы пользователь мог сохранять (сериализовать) изменения, внесенные им в экземпляр класса. Однако в других случаях я не хочу, чтобы пользователь сохранял их изменения, и должен видеть все свойства в сетке свойств как только для чтения. Я не хочу, чтобы пользователи вносили изменения, которые они никогда не смогут сохранить позже. Подобно тому, как MS Word позволяет пользователям открывать документы, которые в настоящее время открыты кем-то другим, но только как только для чтения.

У моего класса есть логическое свойство, которое определяет, должен ли класс быть доступен только для чтения, но можно ли использовать это свойство для динамического добавления атрибутов только для чтения к свойствам класса во время выполнения? Если это не альтернативное решение? Должен ли я переносить свой класс в класс оболочки только для чтения?

4b9b3361

Ответ 1

Неизменность - это область, где С# все еще имеет место для улучшения.. При создании простых неизменяемых типов с помощью свойств readonly возможно, как только вам понадобится более сложный контроль над типом, который вы изменяете, вы начинаете работать в препятствия.

Есть три варианта, которые у вас есть, в зависимости от того, насколько сильно вам нужно "принуждать" поведение только для чтения:

  • Используйте флаг только для чтения в своем типе (например, вы делаете), и позвольте вызывающему абоненту нести ответственность за то, что вы не пытаетесь изменить свойства в типе - если попытка записи сделана, выведите исключение.

  • Создайте интерфейс только для чтения и сохраните его тип. Таким образом вы можете передать тип через этот интерфейс в код, который должен выполнять только чтение.

  • Создайте класс-оболочку, который агрегирует ваш тип и предоставляет только операции чтения.

Первый вариант часто бывает самым простым, поскольку он может потребовать меньше рефакторинга существующего кода, но предлагает наименьшую возможность для автора типа информировать потребителей, когда экземпляр является неизменным, а не когда он не является. Эта опция также обеспечивает наименьшую поддержку от компилятора при обнаружении неправильного использования - и отводит обнаружение ошибок во время выполнения.

Второй вариант удобен, так как реализация интерфейса возможна без значительных усилий по рефакторингу. К сожалению, вызывающие абоненты все равно могут использовать базовый тип и пытаться написать против него. Часто этот параметр сочетается с флагом только для чтения, чтобы гарантировать, что неизменяемость не нарушена.

Третий вариант является самым сильным, поскольку это касается принудительного исполнения, но это может привести к дублированию кода и в большей степени является рефакторингом. Часто полезно комбинировать опции 2 и 3, чтобы установить связь между оберткой только для чтения и полиморфизмом изменяемого типа.

Лично я склоняюсь к третьему варианту при написании нового кода, в котором, как я полагаю, потребуется обеспечить неизменность. Мне нравится то, что невозможно "отбросить" неизменяемую оболочку и он часто позволяет вам избегать написания беспорядочных проверок исключений только для чтения-только-в каждом сеттере.

Ответ 2

Почему не что-то вроде:

private int someValue;
public int SomeValue
{
    get
    {
         return someValue;
    }
    set
    {
         if(ReadOnly)
              throw new InvalidOperationException("Object is readonly");
         someValue= value;
    }

Ответ 3

Я бы использовал класс-оболочку, который сохраняет все только для чтения. Это для масштабируемости, надежности и общей читаемости.

Я не предвижу никаких других способов сделать это, чтобы обеспечить вышеупомянутые три упомянутых преимущества, а также нечто большее. Определенно используйте класс оболочки здесь, на мой взгляд.

Ответ 4

Что-то вроде этой помощи:

class Class1
{
    private bool _isReadOnly;

    private int _property1;
    public int Property1
    {
        get
        {
            return _property1;
        }
        set
        {
            if (_isReadOnly) 
              throw new Exception("At the moment this is ready only property.");
            _property1 = value;
        }
    }
}

При настройке свойств вам нужно поймать исключения.

Надеюсь, это то, что вы ищете.

Ответ 5

Вы не можете получать проверки времени компиляции (например, заданные с ключевым словом readonly), изменяя свойство на чтение только во время выполнения. Таким образом, нет другого способа, чтобы проверить вручную и выбросить исключение.

Но, возможно, лучше перепроектировать доступ к классу. Например, создайте "класс писателя", который проверяет, может ли быть написанный ниже "класс данных" underling или нет.

Ответ 6

Вы можете использовать PostSharp для создания OnFieldAccessAspect, который не будет передавать новое значение в любое поле, когда _readOnly будет установлено значение true. С повторением кода кода прошло и не будет забыто поле.