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


Если я определяю структуру в 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;
}

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

любой и все волшебники Ил-добро пожаловать докажи или опровергни мою теорию.

2 52

2 ответа:

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

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

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

свойство-это не что иное, как инкапсуляция Get метод и / или a 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 с типами структуры. Autoproperties имеют смысл с классами, так как свойства класса могут поддерживать такие функции, как уведомления об обновлении. Даже если ранние версии класса не поддерживают уведомления об обновлениях, если эти версии используют autoproperty, а не поле, это будет означать что будущие версии могут добавлять функции уведомления об обновлении, не требуя, чтобы потребители класса были переработаны. Однако структуры не могут содержательно поддерживать большинство типов объектов, которые можно было бы добавить к свойствам, подобным полям.

кроме того, различия в производительности между полями и свойствами гораздо больше с большими структурами, чем с типами классов. Действительно, большая часть рекомендаций избегать крупных структур является следствием этого разница. Большие структуры на самом деле могут быть очень эффективными, если не копировать их без необходимости. Даже если бы у него была огромная структура HexDecet<HexDecet<HexDecet<Integer>>>, где HexDecet<T> содержит открытые поля F0..F15 типа T, заявления Foo = MyThing.F3.F6.F9; просто потребует чтения одного целого числа из MyThing и хранить его в Foo, хотя MyThing было бы огромным по стандартам структуры (4096 целых чисел, занимающих 16K). Кроме того, можно было бы обновить этот элемент очень легко, например MyThing.F3.F6.F9 += 26;. Напротив, если F0..F15 были авто-свойства, инструкция Foo = MyThing.F3.F6.F9 потребуется копирование 1K данных из MyThing.F3 к временному (назовите его temp1, затем 64 байта данных из temp1.F6 до 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 в рамках, где поля были бы более подходящими, привело к широко распространенным жалобам на компилятор, позволяющий бесполезно вызывать задатчики свойств в структурах только для чтения; следовательно, вызов любого задатчика свойств в структуре только для чтения теперь запрещен, независимо от того, действительно ли задатчик свойств изменит какие-либо поля структуры. Если бы люди просто воздерживались от создания структур, изменяемых с помощью установщиков свойств (создание полей прямой доступ, когда изменчивость была уместна) компиляторам никогда не пришлось бы реализовывать это ограничение.