Как мне узнать, является ли класс неизменным в C #? - PullRequest
16 голосов
/ 27 января 2009

Как узнать, является ли класс неизменным в C #?

Ответы [ 6 ]

32 голосов
/ 27 января 2009

Существует ImmutableObjectAttribute, но это редко используется и плохо поддерживается - и, конечно, не применяется (вы можете пометить изменяемый объект с помощью [ImmutableObject(true)]. AFAIK, единственное, на что это влияет, это то, как IDE обрабатывает атрибуты (т.е. показывать / не показывать параметры именованных свойств).

В действительности вам нужно будет проверить FieldInfo.IsInitOnly, но это относится только к действительно 100% неизменяемым типам (при условии отсутствия злоупотребления отражением и т. Д.); это не помогает с неизменностью эскимо или вещами, которые неизменны на практике, но не в их реализации; то есть их нельзя сделать публично изменяемыми, но теоретически объект поддерживает это.

Классическим примером здесь будет строка ... все "знают", что string является неизменным ... конечно, StringBuilder действительно изменяет строку под капотом. Нет, серьезно ...

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

3 голосов
/ 27 января 2009

Часть проблемы заключается в том, что «неизменный» может иметь несколько значений. Взять, к примеру, ReadOnlyCollection .

Мы склонны считать его неизменным. Но что, если это ReadOnlyCollection ? Кроме того, поскольку на самом деле это просто оболочка вокруг IList, которую я передаю конструктору, что, если я изменю исходный IList?

Хорошим подходом может быть создание атрибута с именем, подобным ReadOnlyAttribute, и пометка классов, которые вы считаете для него доступными только для чтения. Для классов, которые вы не контролируете, вы также можете вести список известных типов, которые вы считаете неизменными.

РЕДАКТИРОВАТЬ: для некоторых хороших примеров различных типов неизменности, прочитайте эту серию сообщений Эрика Липперта: http://blogs.msdn.com/ericlippert/archive/2007/11/13/immutability-in-c-part-one-kinds-of-immutability.aspx

3 голосов
/ 27 января 2009

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

class Foo
{
    public readonly int X
    public readonly int Y
    public Foo(int x, int y, Bar bar)
    {
        this.X = x; 
        bar.ShowYourself(this);
        this.Y = y;
        bar.ShowYourself(this);
    }
}

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

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

Проверка отсутствия свойств на свойствах будет очень плохой эвристикой.

2 голосов
/ 27 января 2009

Насколько мне известно, если это явно не задокументировано, нет способа определить, является ли класс неизменным или нет в C #.

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

Кроме того, проверка на наличие флага IsInitOnly для всех полей класса, опять же с использованием Reflection, может указывать на неизменность, но это не гарантирует этого.

Редактировать: Вот аналогичный вопрос , заданный в отношении языка Java, ответ которого также применим здесь.

1 голос
/ 27 января 2009

Через код, я не уверен, но если вы посмотрите на IL другого неизменяемого типа, такого как строка, вы будете не увидеть инструкцию newobj IL (вы увидите ldstr для строк), возможно, проверка IL создания может быть одним из способов сказать, просто предположение ...

1 голос
/ 27 января 2009

Единственная помощь, которую вы получите от среды выполнения, - это если все поля в классе помечены как «только для чтения». [Edit, см. @ShuggyCoUk] И даже тогда CLR позволит вам писать поверх него. Я только что проверил это. Тьфу.

Вы можете получить объекты FieldInfo из класса с помощью отражения и проверить IsInitOnly.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...