Почему свойства ведут себя так? - PullRequest
2 голосов
/ 12 апреля 2010

С http://csharpindepth.com/Articles/Chapter8/PropertiesMatter.aspx

using System;

struct MutableStruct
{
    public int Value { get; set; }

    public void SetValue(int newValue)
    {
        Value = newValue;
    }
}

class MutableStructHolder
{
    public MutableStruct Field;
    public MutableStruct Property { get; set; }
}

class Test
{    
    static void Main(string[] args)
    {
        MutableStructHolder holder = new MutableStructHolder();
        // Affects the value of holder.Field
        holder.Field.SetValue(10);
        // Retrieves holder.Property as a copy and changes the copy
        holder.Property.SetValue(10);

        Console.WriteLine(holder.Field.Value);
        Console.WriteLine(holder.Property.Value);
    }
} 

1) Почему делается копия (Собственности?)?
2) При изменении кода на holder.Field.Value и holder.Property.Value = 10 я получаю ошибку ниже. Это просто взорвало мой разум.

Невозможно изменить возвращаемое значение MutableStructHolder.Property, поскольку оно не является переменной.

Почему бы мне никогда не было разрешено присваивать значение внутри свойства!?! Оба свойства get / set!

И, наконец, ПОЧЕМУ вы когда-либо хотели бы, чтобы поведение упоминалось в 1 и 2? (Это никогда не подходило для меня, я всегда использовал get only properties).

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

Ответы [ 4 ]

3 голосов
/ 12 апреля 2010

1) Копия Property создается, потому что это struct, а struct является типом значения (в отличие от class) и копируется по значению, а не по ссылке.

2) Ошибка «невозможно изменить возвращаемое значение» возникает из-за природы структур «копировать по значению». Если вы изменили структуру (установив Value на MutableStruct - Property на MutableStructHolder), ваши изменения не будут отражены в ней, потому что вы измените копию структуры, не структура в собственности. Поскольку вы никогда не захотите такого поведения, компилятор C # не позволяет вам этого делать.

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

2 голосов
/ 12 апреля 2010

Чтобы ответить # 1: подумайте, как бы это выглядело без автоматически сгенерированного свойства. У вас будет Property { get { return xxx; } } Вот где копия сделана. То, что выглядит как ссылка на свойство, на самом деле вызывает метод получения. Ожидаете ли вы редактирования на месте, если у вас есть:

private MutableStruct v;
public MutableStruct f()
{
  return v;
}

f() = new MutableStruct();

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

Теперь, если вы думаете, что установщик свойств должен был автоматически вызываться с результирующим значением, позвольте мне отметить, что чрезвычайно сложно невозможно узнать во время компиляции, если вызов один из методов структуры делает изменение (рассмотрите, определена ли структура в другой сборке). И возвращение значения не просто неэффективно, но и безопасно, это может нарушить правильность. Рассмотрим многопоточный сценарий, когда потоки, которые только читали из свойства, защищенного ReaderWriterLock, внезапно записывают обратно в него. Все виды боли и несчастья будут происходить. Таким образом, компилятор C # автоматически устанавливает свойство для результата ваших вычислений, просто не вариант.

РЕДАКТИРОВАТЬ: вам было интересно, почему установка поля в структуре генерирует сообщение об ошибке, но при вызове метода, чтобы сделать то же самое, нет. Ну, у метода могут быть полезные побочные эффекты, поэтому вам все еще нужно вызывать его для временной копии структуры. Рассмотрим следующий вариант:

struct Mutable
{
    public static int Sum = 0;

    public int x;
    public Mutable(int x) { this.x = x; }
    public void Total() { Sum += x; }
}

class Container
{
    public Mutable Field;
    public Mutable Property { get; set; }
}

class Program
{
    static void Main(string[] args)
    {
        Container c = new Container();
        c.Field = new Mutable(1);
        c.Property = new Mutable(2);
        c.Field.Total();
        c.Property.Total();
        Console.Out.WriteLine(Mutable.Sum);
    }
}
2 голосов
/ 12 апреля 2010

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

Что касается вопроса 2: Компилятор C # понимает, что установка переменной непосредственно в struct-object, полученном через свойство, не имеет смысла и, таким образом, дает вам сообщение об ошибке. Если объект, полученный через свойство, имеет установщик или нет, это не изменит это поведение, и вы получите ошибку в любом случае.

Вместо того, чтобы писать о классах и структурах, я предлагаю вам прочитать ответ Лассе Карлсена на вопрос « Разница между структурами и классами »

0 голосов
/ 12 апреля 2010

Структуры передаются по значению, поэтому все, что у вас есть, это копии. Кроме того:

public int Value { get; set; }

является сокращением для

private int _Value;
public int Value { 
   get { return _Value; }  
   set { _Value = value; }
}

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

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