Как узнать, является ли класс неизменным в С#?
Как узнать, является ли класс неизменным в С#?
Ответ 1
Существует ImmutableObjectAttribute
, но это редко используется и плохо поддерживается - и, конечно, не применяется (вы можете отметить изменяемый объект с помощью [ImmutableObject(true)]
. AFAIK, единственное, что это влияет, - это способ, которым IDE обрабатывает атрибуты (т.е. показать/не показать именованные параметры свойств).
В действительности вам нужно будет проверить FieldInfo.IsInitOnly
, но это применимо только к действительно 100% неизменяемым типам (при условии, что они не отражают злоупотребления и т.д.); это не помогает неизменности эскимосов, ни вещей, которые неизменны на практике, но не в их реализации; то есть они не могут быть общедоступными, но теоретически объект поддерживает его.
Классическим примером здесь будет строка... все "знают", что string
неизменен... конечно, StringBuilder
делает мутирует строку под капотом. Нет, серьезно...
Трудно определить неизменность, учитывая это, не говоря уже о ее надежном обнаружении...
Ответ 2
Вы не можете, вы можете только догадываться. Если все поля только для чтения, экземпляры будут неизменными после завершения конструктора. Это важно, если бы у вас было следующее, оно выглядело бы mutable на панели экземпляров.
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);
}
}
Однако, если поле на предположительно неизменяемом классе было коллекцией (и не было только для чтения), то вызов класса неизменяемый, скорее всего, был бы неправильным (поскольку это состояние может измениться)
Обратите внимание, что даже если все поля отображаются только для чтения, разрешено изменять поля.
Проверка на отсутствие настроек свойств будет очень плохой эвристикой.
Ответ 3
Частью проблемы является то, что "неизменяемый" может иметь несколько значений. Возьмем, например, ReadOnlyCollection <T> .
Мы склонны считать его неизменным. Но что, если это ReadOnlyCollection <SomethingCangeable> ? Кроме того, поскольку это действительно просто оболочка вокруг IList, я передаю конструктору, что, если я изменю исходный IList?
Хорошим подходом может быть создание атрибута с именем, таким как ReadOnlyAttribute, и маркировка классов, которые вы считаете доступными только для чтения. Для классов, которые вы не контролируете, вы также можете поддерживать список известных типов, которые вы считаете неизменными.
EDIT: для некоторых хороших примеров разных типов неизменяемости прочитайте эту серию публикаций Эрика Липперта: http://blogs.msdn.com/ericlippert/archive/2007/11/13/immutability-in-c-part-one-kinds-of-immutability.aspx
Ответ 4
Насколько я знаю, если он явно не задокументирован, нет способа определить, является ли класс неизменным или нет в С#.
Однако вы можете использовать Reflection для проверки существования Setters on properties; однако отсутствие настроек не гарантирует неизменности, так как внутреннее состояние может изменять значения этих свойств независимо от того, можете ли вы их явно установить или нет.
Кроме того, проверка флажка "IsInitOnly" для всех полей класса, снова используя Reflection, может указывать на неизменность, но это не гарантирует ее.
Изменить: Здесь аналогичный вопрос, заданный в отношении языка Java, ответ на который также применим здесь.
Ответ 5
Единственная помощь, которую вы получаете из среды выполнения, - это то, что все поля в классе аннотируются с помощью "readonly". [Изменить, см. @ShuggyCoUk] И даже тогда CLR позволит вам писать по нему. Я просто проверил это. Тьфу.
Вы можете получить объекты FieldInfo из класса через отражение и проверить IsInitOnly.
Ответ 6
Через код, я не уверен, но, если вы посмотрите на IL другого неизменяемого типа, например строку, вы будете не видеть инструкцию newobj
IL (вы будете см. ldstr для строк), возможно, проверка IL файла творения может быть одним из способов рассказать, просто догадка...