Свойство - это не что иное, как инкапсуляция метода Get
и / или метода Set
. В CLR есть метаданные, которые указывают, что определенные методы следует рассматривать как свойства, то есть компиляторы должны разрешать некоторые конструкции, которые не допускаются в методах. Например, если X
является свойством чтения-записи Foo
, компилятор переведет Foo.X += 5
в Foo.SET_X_METHOD(Foo.GET_X_METHOD() + 5)
(хотя методы называются по-разному и обычно не доступны по имени).
Хотя autoproperty реализует пару методов get / set, которые обращаются к приватному полю таким образом, чтобы вести себя более или менее как поле, с точки зрения любого кода вне свойства, autoproperty - это пара методов get / set, как и любое другое свойство. Следовательно, утверждение типа Foo.X = 5;
переводится как Foo.SET_X_METHOD(5)
. Поскольку компилятор C # воспринимает это как вызов метода, а методы не содержат метаданных, указывающих, какие поля они читают или пишут, компилятор запрещает вызов метода, если ему не известно, что каждое поле Foo
было записано.
Лично я бы советовал избегать использования autoproperties с типами структур. Автозапчасти имеют смысл с классами, поскольку свойства классов могут поддерживать такие функции, как уведомления об обновлениях. Даже если ранние версии класса не поддерживают уведомления об обновлениях, наличие в этих версиях автоматического свойства, а не поля будет означать, что в будущих версиях можно будет добавлять функции уведомлений об обновлениях, не требуя переделки пользователей класса. Структуры, однако, не могут значимо поддерживать большинство типов функций, которые можно добавить в свойства, подобные полям.
Кроме того, различия в производительности между полями и свойствами намного больше для больших структур, чем для типов классов. Действительно, большая часть рекомендации избегать больших структур является следствием этого различия. Большие структуры на самом деле могут быть очень эффективными, если избежать ненужного их копирования. Даже если бы у вас была огромная структура HexDecet<HexDecet<HexDecet<Integer>>>
, где HexDecet<T>
содержал открытые поля F0
.. F15
типа T
, для оператора, подобного Foo = MyThing.F3.F6.F9;
, просто потребовалось бы прочитать одно целое число из MyThing
и сохранить это к Foo
, хотя MyThing
было бы огромным по структурным стандартам (4096 целых чисел, занимающих 16 КБ). Кроме того, можно очень легко обновить этот элемент, например, MyThing.F3.F6.F9 += 26;
. Напротив, если бы F0
.. F15
были автоматическими свойствами, для оператора Foo = MyThing.F3.F6.F9
потребовалось бы скопировать 1 КБ данных из MyThing.F3
во временный (назовите его temp1
, затем 64 байта данных из * 1031) * до temp2
) прежде чем, наконец, приступим к чтению 4 байтов данных из temp2.F9
. Ик. Хуже того, попытка добавить 26 к значению в MyThing.F3.F6.F9
потребует что-то вроде var t1 = MyThing.F3; var t2 = t1.F6; t2.F9 += 26; t1.F6 = f2; MyThing.F3 = t1;
.
Многие из давних жалоб на «изменяемые типы структур» на самом деле являются жалобами на типы структур со свойствами чтения / записи. Просто замените свойства полями, и проблемы исчезнут.
PS: Иногда бывает полезно иметь структуру, свойства которой обращаются к объекту класса, на который она ссылается. Например, было бы неплохо иметь версию класса ArraySegment<T>
, которая позволяла бы сказать Var foo[] = new int[100]; Var MyArrSeg = New ArraySegment<int>(foo, 25, 25); MyArrSeg[6] += 9;
, и чтобы последний оператор добавил девять к элементу (25 + 6) из foo
. В старых версиях C # это можно было сделать. К сожалению, частое использование autoproperties в Framework, где поля были бы более подходящими, привело к распространенным жалобам на компилятор, позволяющий бесполезно вызывать установщики свойств в структурах только для чтения; следовательно, вызов любого установщика свойства в структуре только для чтения теперь запрещен независимо от того, будет ли установщик свойства фактически изменять какие-либо поля структуры. Если бы люди просто воздерживались от создания структур, изменяемых с помощью установщиков свойств (делая поля непосредственно доступными, когда изменчивость была подходящей), компиляторам никогда бы не пришлось реализовывать это ограничение.