Я пытался перенести голову вокруг этого нарушения FXCop "DoNotDeclareReadOnlyMutableReferenceTypes"
MSDN: http://msdn.microsoft.com/en-us/library/ms182302%28VS.80%29.aspx
Код из MSDN, который вызвал бы это нарушение:
namespace SecurityLibrary
{
public class MutableReferenceTypes
{
static protected readonly StringBuilder SomeStringBuilder;
static MutableReferenceTypes()
{
SomeStringBuilder = new StringBuilder();
}
}
}
Из ответа Jon здесь и здесь, я понимаю, что поле, содержащее ссылку на объект (в этом случае SomeStringBuilder), только для чтения а не сам объект (который создается new StringBuilder()
)
Так беря этот пример, как я изменил бы сам объект, после того как поле имеет ссылку на него? Мне нравится пример Eric Lippert того, как массив только для чтения может быть изменен и хотел бы видеть что-то подобное для любого другого изменяемого ссылочного типа
Поскольку в вопросе представлен класс MutableReferenceTypes, вы не можете мутировать его от любого внешнего вызывающего пользователя, поскольку поле SomeStringBuilder является приватным.
Однако сам класс мог бы мутировать это поле. В настоящее время он этого не делает, но может сделать это в более поздней итерации.
Вот пример метода:
public static void Mutate()
{
SomeStringBuilder.AppendLine("Foo");
}
Вызов метода Mutate приведет к мутации класса, поскольку SomeStringBuilder теперь изменится.
Неизменяемость - это не только текущее воплощение вашего кода, но и защита от будущих ошибок. Не то чтобы все классы должны быть неизменяемыми, но безопаснее всего оставаться последовательным, если вы решили создать неизменяемый тип.
Вы не можете изменить ссылку, но любой вызов (изменяемого) объекта меняет свое состояние.
Следовательно, поскольку SomeStringBuilder
(в этом примере) сам изменяемый, его содержимое может измениться, что может ввести в заблуждение пользователей этого класса, потому что он не предназначен только для чтения.
По сути, readonly
никоим образом не гарантирует, что враги объекта не изменятся, он просто говорит, что ссылка не изменится.
readonly означает, что вы не можете изменить эталонную постконструкцию.
Официальная позиция FXCop заключается в том, что он рекомендует объявлять только типы, которые не могут быть изменены только для чтения
. Поэтому что-то вроде строки
допустимо, потому что значение объекта нельзя изменить. Однако значение StringBuilder
можно изменить, но если сделать его доступным только для чтения, вы не сможете назначить поле другому экземпляру StringBuilder
или null
после выполнения конструктора.
Я не согласен с FXCop по этому правилу. Пока кто-то понимает, что это просто принудительное исполнение, что ссылка не может изменить постконструирование, тогда не будет путаницы.
Обратите внимание, что типы значений становятся неизменными с помощью ключевого слова readonly
, а ссылочные типы - нет.
namespace SecurityLibrary
{
public class MutableReferenceTypes
{
static protected readonly StringBuilder SomeStringBuilder;
static MutableReferenceTypes()
{
// allowed
SomeStringBuilder = new StringBuilder();
}
void Foo()
{
// not allowed
SomeStringBuilder = new StringBuilder();
}
void Bar()
{
// allowed but FXCop doesn't like this
SomeStringBuilder.AppendLine("Bar");
}
}
}
Вы не можете изменять значение объекта. В этом суть правила. Любое поле, объявленное только для чтения, должно фактически быть таким, только для чтения. Наличие изменяемой ссылки только для чтения - оксюморон. Если вы можете изменить значение того, на что "указывает" поле, тогда оно больше не будет доступно только для чтения. На самом деле нет функциональной разницы между присвоением значения всех членов некоторого объекта A какому-либо объекту B, представленным полем, или простым присвоением A этому полю (когда они одного типа), однако только один из них действителен, когда поле объявлен только для чтения, но поскольку вы можете эффективно изменять значение того, что представлено в поле, это, как уже было сказано, не совсем readonly
Можно удалить все разрешения для анонимного пользователя
trac-admin /path/to/projenv permission remove anonymous '*'
Для получения подробной информации см. Трассировка документов разрешений
Трассировка по умолчанию предлагает две различные группы разрешений:
В документах описывается, как изменять значения по умолчанию для группы и как можно формировать новые наборы разрешений в разделе группы разрешений .
-121--4903810-Floor ((log2 (N )/8) + 1) байт
-121--1466486- .Net содержит список допустимых типов постоянных ссылок, StringBuilder
не является одним из них.
Претензия заключается в том, что то, что вы создаете, не является незыблемым, хотя статический конструктор вызывается один раз и класс инициализируется один раз, это все, что остается прежним, остальное может изменяться. Один поток может вызвать .Append ()
, затем другой... вы видите, как последовательность builder сам мутирует и на самом деле не только для чтения
, потому что он постоянно меняет состояния/мутирует.
Объявление только для чтения
действительно является неправильным, поскольку сам объект, на который имеется ссылка, постоянно изменяется.