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

Я знаю, как использовать свойства, и я понимаю, что они неявно называют базовыми 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) Но разве который не побеждает целую цель наличия свойств только для чтения? Разве не было бы более эффективно, если бы свойства имели способность также обнаружить, пытаемся ли мы получить доступ к членам объекта, возвращенного, получают средство доступа (предполагающий, что отступающее поле имеет ссылочный тип)?

спасибо

10
задан Kevin Panko 16 June 2010 в 20:16
поделиться

13 ответов

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

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

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

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

13
ответ дан 3 December 2019 в 13:11
поделиться
  1. Нет, это не отменяет назначение свойств только для чтения.
  2. Можно использовать свойства только для чтения, которые не позволяют пользователю изменять базовые данные. Например, ваше свойство может возвращать System.Collections.ObjectModel.ReadOnlyCollection , даже если базовым типом является List . Это, конечно, не помешает пользователю изменять свойства элементов в коллекции.
9
ответ дан 3 December 2019 в 13:11
поделиться

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

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

2
ответ дан 3 December 2019 в 13:11
поделиться

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

a.b.i = 100;

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

a.b = new B();

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

2
ответ дан 3 December 2019 в 13:11
поделиться

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

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
ответ дан 3 December 2019 в 13:11
поделиться

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

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

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

4
ответ дан 3 December 2019 в 13:11
поделиться

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

27
ответ дан 3 December 2019 в 13:11
поделиться

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

19
ответ дан 3 December 2019 в 13:11
поделиться

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

6
ответ дан 3 December 2019 в 13:11
поделиться

Вы спросите:

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

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

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

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

5
ответ дан 3 December 2019 в 13:11
поделиться

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

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

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

1
ответ дан 3 December 2019 в 13:11
поделиться

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

2
ответ дан 3 December 2019 в 13:11
поделиться

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

2
ответ дан 3 December 2019 в 13:11
поделиться
Другие вопросы по тегам:

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