Разве это не разрушает всю цель наличия свойств только для чтения? - 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 ]

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

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

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

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

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

Представьте себе класс, подобный этому:

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

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

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

9 голосов
/ 16 июня 2010
  1. Нет, это не отменяет назначение свойств только для чтения.
  2. Можно использовать свойства только для чтения, которые не позволяют пользователю изменять базовые данные.Например, ваше свойство может вернуть System.Collections.ObjectModel.ReadOnlyCollection, даже если базовый тип - List.Это, конечно, не помешает пользователю изменить свойства элементов в коллекции.
6 голосов
/ 16 июня 2010

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

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

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

Разве это не побеждает всю цель иметь свойства только для чтения?

Но посмотрите: ваш B.i участник является открытым полем .

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

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

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

Ссылка неизменности является популярной функцией запроса. Жаль, что он настолько не соответствует CLS. У очень немногих языков есть такое понятие, я знаю только C ++ (но мало что получаю).

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

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

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

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

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, если вы не читаете читы, у вас есть доступ только для чтения ко всем именам, ноне могу изменить ни одного из них.

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

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

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

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

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