Разве это не разрушает всю цель наличия свойств только для чтения? - PullRequest
10 голосов
/ 16 июня 2010

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

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

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

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

спасибо

Ответы [ 13 ]

2 голосов
/ 16 июня 2010

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

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

2 голосов
/ 16 июня 2010

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

a.b.i = 100;

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

a.b = new B();

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

1 голос
/ 17 июня 2010

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

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

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

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