Почему необходимо вызывать this () для структуры, чтобы использовать автоматические свойства в c #?

StackOverflow https://stackoverflow.com/questions/272153

Вопрос

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

public struct Address
{
    public Address(string line1, string line2, string city, string state, string zip)
    {
        Line1 = line1;
        Line2 = line2;
        City = city;
        State = state;
        Zip = zip;
    }

    public string Line1 { get; protected set; }
    public string Line2 { get; protected set; }
    public string City { get; protected set; }
    public string State { get; protected set; }
    public string Zip { get; protected set; }
}

Когда я пытаюсь собрать файл, появляется сообщение об ошибке The 'this' object cannot be used before all of its fields are assigned to. Это можно решить, изменив конструктор так, чтобы он вызывал цепочечный вызов конструктора по умолчанию, например:

public Address(string line1, string line2, string city, string state, string zip): this()
{
    Line1 = line1;
    Line2 = line2;
    City = city;
    State = state;
    Zip = zip;
}

Мой вопрос: почему это работает и что происходит? У меня есть предположение, и я пытался доказать это, глядя на ИЛ, но я шучу, только если думаю, что могу сломать ИЛ. Но я предполагаю, что автоматические свойства работают, когда компилятор создает поля для ваших свойств за кулисами. К этим полям нельзя получить доступ через код, все настройки и получение должны быть сделаны через свойства. При создании структуры конструктор по умолчанию не может быть определен явно. Так что за кулисами компилятор должен генерировать конструктор по умолчанию, который устанавливает значения полей, которые разработчик не может видеть.

Любые волшебники IL могут доказать или опровергнуть мою теорию.

Это было полезно?

Решение

Примечание. Начиная с C # 6, это не требуется, но вы все равно должны использовать автоматически реализуемые свойства только для чтения с C # 6 ...

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

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

Другие советы

Свойство - это не что иное, как инкапсуляция метода 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 # воспринимает это как вызов метода, а методы не содержат метаданных, указывающих, какие поля они читают или пишут, компилятор запретит вызов метода, если ему не известно, что каждое поле HexDecet<HexDecet<HexDecet<Integer>>> было написано.

Лично я бы советовал избегать использования autoproperties с типами структур. Автозапчасти имеют смысл с классами, поскольку свойства классов могут поддерживать такие функции, как уведомления об обновлениях. Даже если ранние версии класса не поддерживают уведомления об обновлениях, наличие в этих версиях автоматического свойства, а не поля будет означать, что в будущих версиях можно будет добавлять функции уведомлений об обновлениях, не требуя переделки пользователей класса. Структуры, однако, не могут значимо поддерживать большинство типов функций, которые можно добавить в свойства, подобные полям.

Кроме того, различия в производительности между полями и свойствами намного больше для больших структур, чем для типов классов. Действительно, большая часть рекомендации избегать больших структур является следствием этого различия. Большие структуры на самом деле могут быть очень эффективными, если избежать ненужного их копирования. Даже если бы у вас была огромная структура HexDecet<T>, где F0 содержал открытые поля F15 .. T типа Foo = MyThing.F3.F6.F9;, для оператора типа MyThing просто потребовалось бы прочитать одно целое число из MyThing.F3.F6.F9 += 26; и сохранить это к Foo = MyThing.F3.F6.F9, хотя MyThing.F3 было бы огромным по структурным стандартам (4096 целых чисел, занимающих 16 КБ). Кроме того, можно очень легко обновить этот элемент, например, temp1. Напротив, если бы temp1.F6 .. temp2 были автоматическими свойствами, для оператора temp2.F9 потребовалось бы скопировать 1 КБ данных из MyThing.F3.F6.F9 во временный (назовите его var t1 = MyThing.F3; var t2 = t1.F6; t2.F9 += 26; t1.F6 = f2; MyThing.F3 = t1;, затем 64 байта данных из <= > до ArraySegment<T>) прежде чем приступить к чтению 4 байтов данных из Var foo[] = new int[100]; Var MyArrSeg = New ArraySegment<int>(foo, 25, 25); MyArrSeg[6] += 9;. Ик. Хуже того, попытка добавить 26 к значению в foo потребует что-то вроде <=>.

Многие из давних жалоб на & типы изменяемых структур " действительно жалуются на типы структур со свойствами чтения / записи. Просто замените свойства полями, и проблемы исчезнут.

PS. Иногда бывает полезно иметь структуру, свойства которой обращаются к объекту класса, на который он ссылается. Например, было бы неплохо иметь версию класса <=>, которая позволяла бы сказать <=>, и чтобы последний оператор добавил девять к элементу (25 + 6) из <=>. В старых версиях C # это можно было сделать. К сожалению, частое использование autoproperties в Framework, где поля были бы более подходящими, привело к распространенным жалобам на компилятор, позволяющий бесполезно вызывать установщики свойств в структурах только для чтения; следовательно, вызов любого установщика свойства в структуре только для чтения теперь запрещен независимо от того, будет ли установщик свойства фактически изменять какие-либо поля структуры. Если бы люди просто воздерживались от создания структур, изменяемых через установщики свойств (делая поля непосредственно доступными, когда изменчивость была подходящей), компиляторам никогда бы не пришлось реализовывать это ограничение.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top