Свойства - по значению или по ссылке? - PullRequest
7 голосов
/ 11 марта 2011

У меня есть следующая публичная собственность, которая выставляет Arraylist:

public ArrayList SpillageRiskDescriptions
        {
            get
            {
                return _SpillageRiskDescriptions;
            }
            set
            {
                _SpillageRiskDescriptions = value;
            }
        }

В другом месте я звоню

SpillageRiskDescriptions.Add("VENTILATE AREA");
SpillageRiskDescriptions.Add("DO NOT ALLOW SPILLAGE TO ENTER MAINS");

Кажется, что они добавляют элементы в приватный ArrayList _SpillageRiskDescriptions (через свойство), тогда как я ожидал, что это вызовет проблему. Поэтому правильно ли я считаю, что свойства возвращают ссылку на исходную переменную и не передают ее по значению ? Это потому что ArrayList является ссылочным типом? Произойдет ли то же самое с int (например?)

Ответы [ 6 ]

11 голосов
/ 11 марта 2011

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

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

8 голосов
/ 11 марта 2011

Другие ответы правильно ответили на ваш основной вопрос: значение свойства ссылочного типа является ссылкой на экземпляр ссылочного типа.

Большой вопрос: "а что ты с этим делаешь?"Предположительно, вы не хотите получить код, который может получить список, чтобы иметь возможность изменить его.

Здесь есть несколько вариантов.

Во-первых, независимо от того, что вы делаете, я рекомендую прекратить использование ArrayList прямо сейчас и начать использовать более современный, безопасный тип для хранения списка вещей.List<string> сразу приходит на ум.

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

В-третьих, у нас есть более компактный синтаксис для «тривиального» свойства.Вы могли бы сказать

public List<string> SpillageListDescriptions { get; private set; }

, и компилятор сгенерирует для вас вспомогательное поле.

Обратите внимание, что List<string> все еще допускает мутацию.

Если все, о чем заботится клиент, - это возможность перебирать список по одной за раз, то вы можете сделать это:

private List<string> descriptions = whatever;
public IEnumerable<string> SpillageListDescriptions 
{ 
    get 
    {
        if (descriptions == null) yield break;
        foreach(var description in descriptions) 
            yield return description;
    }
}

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

Или вы можете сделать:

private List<string> descriptions = whatever;
public IList<string> SpillageListDescriptions 
{ 
    get 
    {
        return new ReadOnlyCollection<string>(descriptions); 
    }
}

И теперь у вызывающей стороны естьпросмотр списка только для чтения, который вызовет исключение, если они попытаются изменить его.

2 голосов
/ 11 марта 2011

C # возвращает объекты по ссылке.

Единственными вещами, которые не возвращаются по значению, являются:

Примитивные типы.
Типы структур.
Перечисления.

1 голос
/ 11 марта 2011

Это не имеет ничего общего с тем, является ли это собственностью; это тип данных свойства. В этом случае вы используете ArrayList, который является классом, который передается по ссылке. Если свойство было напечатано как int, оно будет передано по значению.

0 голосов
/ 11 марта 2011

Это не имеет никакого отношения к собственности.

В этом случае вы передаете ссылку на список массивов по значению.

Если вы делаете что-то вроде

      void AddSomethingToArrayList(ArrayList spillageRiskDescriptions){
           spillageRiskDescriptions.Add("Something");
      }

тогда ссылка на список массивов будет изменена.

Если бы вы сделали что-то вроде

      void ReassignArrayList(ArrayList spillageRiskDescriptions){
           spillageRiskDescriptions = new ArrayList();
           spillageRiskDescriptions.Add("Something");
      }

тогда исходная ссылка на список массивов вообще не будет изменена.

Но если вы передадите ссылку по ссылке, например:

      void ReassignArrayListByRef(ref ArrayList spillageRiskDescriptions){
           spillageRiskDescriptions = new ArrayList();
           spillageRiskDescriptions.Add("Something");
      }

тогда ваше свойство получит новый список массивов с одним элементом.

0 голосов
/ 11 марта 2011

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

// this is how the getter method looks like
public ArrayList get_SpillageRiskDescriptions()
{
    return _SpillageRiskDescriptions;
}

// this is how the setter method looks like
public void set_SpillageRiskDescriptions(ArrayList value)
{
    _SpillageRiskDescriptions = value;
}

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

Чтобы ответить на ваши конкретные вопросы:

Поэтому я прав, считая, что свойства возвращают ссылку наисходная переменная и не передавая ее по значению ?

Нет, используя геттер, вы не получите ссылку на поле _SpillageRiskDescriptions.Вы получаете значение поля, которое является ссылкой на (динамически размещенный) экземпляр ArrayList.

Это потому, что ArrayList является ссылочным типом?

Да, ArrayList является ссылочным типом, и, таким образом, вы получаете ссылку на конкретный экземпляр ArrayList.

Произойдет ли то же самое с int (дляпример?)

Да и нет. Да , вы получите значение поля intno , int является типом значения, поэтому, если вы измените значение без явного его сброса, основное поле не будет затронуто.

...