Неизменные ссылочные типы только для чтения и Нарушение FXCop: не объявляйте изменяемые ссылочные типы только для чтения

Я пытался перенести голову вокруг этого нарушения 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 того, как массив только для чтения может быть изменен и хотел бы видеть что-то подобное для любого другого изменяемого ссылочного типа

7
задан Community 23 May 2017 в 12:16
поделиться

5 ответов

Поскольку в вопросе представлен класс MutableReferenceTypes, вы не можете мутировать его от любого внешнего вызывающего пользователя, поскольку поле SomeStringBuilder является приватным.

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

Вот пример метода:

public static void Mutate()
{
    SomeStringBuilder.AppendLine("Foo");
}

Вызов метода Mutate приведет к мутации класса, поскольку SomeStringBuilder теперь изменится.

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

3
ответ дан 7 December 2019 в 03:15
поделиться

Вы не можете изменить ссылку, но любой вызов (изменяемого) объекта меняет свое состояние.

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

По сути, readonly никоим образом не гарантирует, что враги объекта не изменятся, он просто говорит, что ссылка не изменится.

0
ответ дан 7 December 2019 в 03:15
поделиться

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");
        }
    }
}
6
ответ дан 7 December 2019 в 03:15
поделиться

Вы не можете изменять значение объекта. В этом суть правила. Любое поле, объявленное только для чтения, должно фактически быть таким, только для чтения. Наличие изменяемой ссылки только для чтения - оксюморон. Если вы можете изменить значение того, на что "указывает" поле, тогда оно больше не будет доступно только для чтения. На самом деле нет функциональной разницы между присвоением значения всех членов некоторого объекта A какому-либо объекту B, представленным полем, или простым присвоением A этому полю (когда они одного типа), однако только один из них действителен, когда поле объявлен только для чтения, но поскольку вы можете эффективно изменять значение того, что представлено в поле, это, как уже было сказано, не совсем readonly

0
ответ дан 7 December 2019 в 03:15
поделиться

Можно удалить все разрешения для анонимного пользователя

trac-admin /path/to/projenv permission remove anonymous '*'

Для получения подробной информации см. Трассировка документов разрешений
Трассировка по умолчанию предлагает две различные группы разрешений:

  • аутентифицированная
  • анонимная

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

-121--4903810-

Floor ((log2 (N )/8) + 1) байт

-121--1466486-

.Net содержит список допустимых типов постоянных ссылок, StringBuilder не является одним из них.

Претензия заключается в том, что то, что вы создаете, не является незыблемым, хотя статический конструктор вызывается один раз и класс инициализируется один раз, это все, что остается прежним, остальное может изменяться. Один поток может вызвать .Append () , затем другой... вы видите, как последовательность builder сам мутирует и на самом деле не только для чтения , потому что он постоянно меняет состояния/мутирует.

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

0
ответ дан 7 December 2019 в 03:15
поделиться
Другие вопросы по тегам:

Похожие вопросы: