Разве это не разрушает всю цель наличия свойств только для чтения?

Я знаю, как использовать свойства, и я понимаю, что они неявно называют базовые get и set аксессоры, в зависимости от того, пишем ли мы или читаем из свойства.

static void Main(string[] args)
{
    A a = new A();
    (a.b).i = 100;

}

class A 
{
    private B _b = new B();
    public B b
    {
        get { return _b; }
    }
}
class B  
{
    public int i;
}

В самом деле, код (a.b).i = 100; заключается в том, что первое свойство get accessor возвращает ссылку на объект _b, и как только у нас есть эта ссылка, мы можем получить доступ к членам _b’s и изменить их значения.

Таким образом, в нашем примере свойство только для чтения запрещает внешнему коду изменять значение ссылочной переменной _b, но это не предотвращает доступ внешнего кода к членам _b’s.

Таким образом, кажется, что свойство может только определить, пытаемся ли мы читать или записывать переменную (в нашем случае переменную _b), находящуюся в стеке, тогда как ее не удалось определить, пытались ли они также писать члены объекта, к которому указывает переменная в стеке (при условии, что эта переменная имеет ссылочный тип).

a) Но разве это не разрушает всю цель наличия свойств только для чтения? Не было бы более эффективным, если бы свойства имели возможность также обнаруживать, пытались ли получить доступ к элементам объекта, возвращаемым get accessor (при условии, что поле поддержки имеет ссылочный тип)?

Благодарю вас

Ответ 1

Представьте себе такой класс:

public class A
{
    private List<int> _myList<int> = new List<int>();
    public List<int> MyList { get { return _myList; } }
}

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

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

Ответ 2

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

Ответ 3

Ваша ссылка доступна только для чтения, а не для вашего объекта.

Ответ 4

  • Нет, это не отменяет цели свойств, доступных только для чтения.
  • Можно использовать свойства только для чтения, которые не позволяют пользователю изменять базовые данные. Например, вы можете вернуть свое свойство System.Collections.ObjectModel.ReadOnlyCollection, хотя базовый тип - это List. Это, конечно, не помешает пользователю изменять свойства элементов в коллекции.

Ответ 5

Конечно, вы можете получить доступ к B.i; это public. Вы думаете, что, поскольку _b является закрытым, все методы должны быть приватными, когда вы выбираете A? В этом случае это довольно бесполезно, поскольку вы не сможете использовать B для чего-либо.

Ответ 6

Вы спрашиваете:

Не побеждает ли цель? наличия свойств только для чтения?

Но посмотрите: ваш член B.i - это публичное поле.

Я прошу вас, а затем: что такое цель иметь общедоступное поле? Это имеет смысл, если вы хотите, чтобы пользователи вашего кода могли изменять это значение поля. Если вы этого не хотите, это должно быть частное поле или (если вы хотите предоставить доступ для чтения, но не для записи) свойство с частным аксессуаром set.

Итак, вот ваш ответ. private B _b выполняет свою задачу в коде, который вы опубликовали достаточно хорошо (_b не может быть внешне установлен на что-то новое), так же как public int i выполняет свою задачу одинаково хорошо (i может быть изменен извне).

Ответ 7

Непрерывность ссылок - популярный запрос функции. Слишком плохо, что он настолько несовместим с CLS. Очень немногие языки имеют это понятие, я знаю только С++ (но не выхожу много).

Ключевая проблема, которая должна выполняться CLR. С++ не нужно принудительно применять это во время выполнения, требуется только компилятор С++ для обеспечения соблюдения контрактов const. Он не имеет никакой поддержки для языкового взаимодействия, за исключением болтов, подобных COM.

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

Ответ 8

В качестве второстепенной точки вам не нужно писать (a.b).i = 100;, но просто

a.b.i = 100;

Вернемся к вашему вопросу, я не думаю, что это побеждает цель. Вы все еще не можете сделать следующее:

a.b = new B();

потому что нет общедоступного набора(). Если вы хотите, чтобы член я класса B был доступен только для чтения, вы можете сделать то же самое, что и вы, для члена _b класса A, сделав его закрытым и предоставив публичный get(), но не set(). Сверху моя голова делает то, что вы предлагаете, может привести к множеству неожиданных консистенций (я уверен, что разработчики языка этого не заметили).

Ответ 9

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

Некоторые классы (например, String-объект в Java, и я верю в С#), являются полностью неизменными, поскольку, поскольку другие только частично изменяемы. Рассмотрим стиль ActiveRecord для объекта, для которого большинство полей являются изменяемыми, но идентификатор является неизменным. Если ваш класс содержит ActiveRecord в свойстве только для чтения, внешние классы не могут поменять его на другой объект ActiveRecord и, таким образом, изменить идентификатор, который может нарушить предположения в вашем классе.

Ответ 10

Я не согласен. Ваше свойство относится к классу B, а не к членам класса B. Это означает, что вы не можете назначить новый объект b. Это не означает, что публичные члены B внезапно становятся частными.

Ответ 11

readonly применяется к свойству класса, а не к объекту, к которому относится свойство. Это не позволяет вам писать a.b = new B();, и это все, что он делает. Он не устанавливает ограничений на то, что вы можете сделать с объектом, как только вы получите ссылку на него. Я думаю, что вы обнаруживаете, что readonly имеет наибольший смысл при применении к типам значений или неизменяемым типам классов.

Ответ 12

Другой вариант использования:

interface INamedPerson
{
    String Name { get; }
}

class Bob : INamedPerson
{
    public String Name { get; set; }
}

class Office
{
    // initialisation code....

    public INamedPerson TheBoss { get; }

    public IEnumerable<INamedPerson> Minions { get; }
}

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

Ответ 13

Ах. Инкапсуляция делает экземпляр класса наследованием уровня доступа класса. Выявление типа B как открытого свойства типа A. 'B.i' является общедоступным, поэтому оно должно быть доступно извне таким же образом. A.b 'является общедоступным.

A.b возвращает ссылку на частный тип B, однако тип B имеет общедоступное поле i. Я понимаю, что вы можете установить поле я в B, но вы не можете установить свойство b из A извне. Свойство типа B для A выполняется только для чтения, однако ссылка на тип B не определяет один и тот же доступ только для чтения к его полям.

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