Я использую автоматически реализованные свойства. Я думаю, что самый быстрый способ исправить следующее - объявить собственную переменную поддержки?
public Point Origin { get; set; }
Origin.X = 10; // fails with CS1612
Сообщение об ошибке: невозможно изменить возвращаемое значение выражения, поскольку оно не является переменной
Была предпринята попытка изменить тип значения, являющийся результатом промежуточного выражения. Поскольку значение не сохраняется, оно не изменится.
Чтобы устранить эту ошибку, сохраните результат выражения в промежуточном значении или используйте ссылочный тип для промежуточного выражения.
c#
variables
struct
immutability
Павел
источник
источник
Ответы:
Это потому, что
Point
это значение типа (struct
).Из-за этого, когда вы
Origin
обращаетесь к свойству, вы получаете доступ к копии значения, хранящегося в классе, а не самого значения, как если бы вы использовали ссылочный тип (class
), поэтому, если вы установите для негоX
свойство, тогда вы устанавливаете свойство на копии, а затем отбрасывает его, оставляя исходное значение без изменений. Это, вероятно, не то, что вы хотели, поэтому компилятор предупреждает вас об этом.Если вы хотите изменить только
X
значение, вам нужно сделать что-то вроде этого:источник
Использование резервной переменной не поможет.Point
Тип представляет собой тип значения.Вам необходимо присвоить целое значение Point свойству Origin:
Проблема заключается в том, что при доступе к свойству Origin то, что возвращается,
get
является копией структуры Point в автоматически создаваемом поле свойств Origin. Следовательно, ваша модификация поля X этой копии не повлияет на базовое поле. Компилятор обнаруживает это и выдает ошибку, поскольку эта операция совершенно бесполезна.Даже если бы вы использовали свою собственную переменную поддержки, вы
get
бы выглядели так:Вы все равно будете возвращать копию структуры Point, и вы получите ту же ошибку.
Хм ... прочитав ваш вопрос более внимательно, возможно, вы действительно хотите изменить вспомогательную переменную прямо из вашего класса:
Да, это было бы то, что вам нужно.
источник
К настоящему времени вы уже знаете, что является источником ошибки. В случае, если конструктор не существует с перегрузкой для получения вашего свойства (в данном случае
X
), вы можете использовать инициализатор объекта (который сделает всю магию за кулисами). Не то, что вам не нужно делать свои структуры неизменяемыми , а просто давать дополнительную информацию:Это возможно, потому что за кадром это происходит:
Это выглядит очень странно, совсем не рекомендуется. Просто перечисление альтернативного пути. Лучший способ сделать это - сделать структуру неизменной и предоставить правильный конструктор.
источник
Origin.Y
? Учитывая свойство типаPoint
, я думаю , идиоматических способ изменить толькоX
будетvar temp=thing.Origin; temp.X = 23; thing.Origin = temp;
. Преимущество идиоматического подхода состоит в том, что ему не нужно упоминать членов, которые он не хочет изменять, - возможность, которая возможна только потому, чтоPoint
она изменчива. Я озадачен философией, которая гласит, что, поскольку компилятор не может допустить,Origin.X = 23;
нужно разработать структуру, требующую подобного кодаOrigin.X = new Point(23, Origin.Y);
. Последнее кажется мне действительно неприглядным.X
иY
конкретному конструктору). Теперь он теряет момент, когда можно сделатьPoint p = new Point()
. Я знаю, почему это действительно требуется для структуры, поэтому нет смысла думать об этом. Но у вас есть крутая идея обновить только одно свойство, какX
?Object
. Они не Каждое определение типа значения фактически определяет два вида вещей: тип хранилища (используется для переменных, слотов массивов и т. Д.) И тип объекта кучи, иногда называемый «коробочным» типом (используется, когда значение типа значения хранится в местоположении ссылочного типа).Помимо обсуждения плюсов и минусов структур по сравнению с классами, я склонен смотреть на цель и подходить к проблеме с этой точки зрения.
При этом, если вам не нужно писать код за свойством get и set методов (как в вашем примере), то не будет ли проще просто объявить
Origin
как поле класса, а не как свойство? Я должен подумать, что это позволит вам достичь своей цели.источник
Проблема в том, что вы указываете на значение, находящееся в стеке, и оно не будет возвращено обратно в свойство orignal, поэтому C # не позволяет вам возвращать ссылку на тип значения. Я думаю, что вы можете решить эту проблему, удалив свойство Origin и вместо этого воспользовавшись открытым полем, да, я знаю, что это не очень хорошее решение. Другое решение - не использовать Point, а вместо этого создать собственный тип Point в качестве объекта.
источник
Point
это член ссылочного типа, он не будет в стеке, он будет в куче в памяти содержащего объекта.Я предполагаю, что выгода заключается в том, что вы пытаетесь назначить под-значения объекта в выражении, а не сам объект. В этом случае вам необходимо назначить весь объект Point, поскольку типом свойства является Point.
Надеюсь, у меня есть смысл
источник
Point
это был изменяемый тип класса, исходный код установил бы поле или свойствоX
в объекте, возвращаемом свойствомOrigin
. Я не вижу оснований полагать, что это оказало бы желаемый эффект на объект, содержащийOrigin
свойство. Некоторые классы Framework имеют свойства, которые копируют их состояние в новые изменяемые экземпляры классов и возвращают их. Такое проектирование имеет то преимущество, что позволяет коду, например,thing1.Origin = thing2.Origin;
устанавливать состояние источника объекта, совпадающему с другим, но он не может предупреждать о подобном кодеthing1.Origin.X += 4;
.Просто удалите свойство «get set», как показано ниже, и тогда все работает как всегда.
В случае примитивных типов instread используйте get; set; ...
источник
Я думаю, что многие люди запутываются здесь, эта конкретная проблема связана с пониманием того, что свойства типа значения возвращают копию типа значения (как с методами и индексаторами), и к полям типа значения обращаются напрямую . Следующий код делает именно то, что вы пытаетесь достичь, напрямую обращаясь к полю поддержки свойства (примечание: выражение свойства в его подробной форме с помощью поля поддержки является эквивалентом свойства auto, но имеет то преимущество, что в нашем коде мы можем получить доступ к вспомогательному полю напрямую):
Ошибка, которую вы получаете, является косвенным следствием непонимания того, что свойство возвращает копию типа значения. Если вам возвращается копия типа значения и вы не присваиваете ее локальной переменной, то любые изменения, которые вы вносите в эту копию, никогда не будут считаны, и поэтому компилятор выдаст это как ошибку, поскольку это не может быть преднамеренным. Если мы присвоим копию локальной переменной, мы сможем изменить значение X, но оно будет изменено только для локальной копии, что исправляет ошибку времени компиляции, но не будет иметь желаемого эффекта изменения свойства Origin. Следующий код иллюстрирует это, так как ошибка компиляции исчезла, но утверждение отладки не выполнится:
источник