C # Структуры "это = ...." - PullRequest
35 голосов
/ 10 марта 2012

Я только что просматривал файл в отражателе и видел это в конструкторе структуры:

this = new Binder.SyntaxNodeOrToken();

Я раньше не видел этой терминологии.Может кто-нибудь объяснить, что означает это назначение в C #.Это сложно для Google.

Ответы [ 2 ]

59 голосов
/ 10 марта 2012

Заменяет значение, в основном. Он эффективно копирует все поля справа налево ... за исключением того, что он работает, даже если поля доступны только для чтения. И да, это действительно выглядит отчетливо странно, и это несколько страшно.

Пример:

using System;

class Test
{
    static void Main()
    {
        Point point = new Point(10, 20);
        point.ReplaceWith(new Point(2, 3));
        Console.WriteLine(point); // (2, 3)
    }
}

struct Point
{
    private readonly int x;
    private readonly int y;

    public Point(int x, int y)
    {
        this.x = x;
        this.y = y;
    }

    public void ReplaceWith(Point other)
    {
        this = other;
    }

    public override string ToString()
    {
        return string.Format("({0}, {1})", x, y);
    }
}

Для получения дополнительной информации прочитайте раздел 7.6.7 спецификации C # 4, который включает в себя:

  • [текст об использовании в конструкторе структуры]

  • Когда this используется в первичном выражении внутри метода экземпляра или метода доступа к экземпляру структуры, оно классифицируется как переменная. Тип переменной - это тип экземпляра структуры, в которой происходит использование.

    • Если метод или метод доступа не являются итератором, переменная this представляет структуру, для которой был вызван метод или метод доступа, и ведет себя точно так же, как параметр ref типа структуры.

    • [текст об итераторах]

5 голосов
/ 11 марта 2012

Если s1 и s2 являются структурами типа Foo, с полями f1, f2 и f3, оператор s1 = s2 семантически эквивалентен

s1.f1 = s2.f1;
s1.f2 = s2.f2;
s1.f3 = s2.f3;

за исключением того, что не следует делать никаких предположений относительно порядка операций присваивания (или даже относительного порядка чтения и записи; сгенерированный код может, например, считывать все три поля в регистры, а затем записывать все три поля).Все поля будут скопированы независимо от того, являются ли они открытыми или закрытыми, изменяемыми или так называемыми неизменяемыми.Никакие свойства getter или setters не будут вызваны;ни исходная, ни целевая структура не получат никакого уведомления о том, что поля структур дублируются или перезаписываются.

Оператор this = new Foo(whatever); на C # (*) эквивалентен

Foo temp;
call Foo's constructor (out temp, whatever);
this.f1 = temp.f1;
this.f2 = temp.f2;
this.f3 = temp.f3;

(*) Семантика конструктора структуры в vb.net различна

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

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

// Assume myKVP is a field of type KeyValuePair<Wizzle, int>
rr = new KeyValuePair<Wizzle, int>(myKVP.Key, myKVP.Value + 1);

делает его похожим на myKVP, ссылающийся надругой экземпляр после присвоения отличается от того, что он держал до этого, когда то, что на самом деле происходит:

// Assumes backing fields are named _Key and _Value
// Note that C# won't allow one to write private fields directly, but the
// act of copying one struct instance to another copies all the fields,
// public and private, from the source instance to the destination.
KeyValuePair<Wizzle, int> temp;
temp._Key = myKVP.Key; // Constructor has access to backing fields
temp._Value = myKVP.Value+1;
myKVP._Key = temp._Key; // Struct assignment copies all fields, public and private
myKVP.Value = temp.Value;

Другими словами, оператор не заставляет myKVP сообщать другому экземпляру;вместо этого он создает новый экземпляр, изменяет старый экземпляр, перезаписывая его поля полями нового экземпляра, а затем отбрасывает новый экземпляр.Если какой-то код оценивает myKVP.ToString() во время выполнения вышеуказанного присваивания, мутация повлияет на экземпляр myMVP, который был напечатан.

Структуры могут иметь полезную семантику, но так называемые "неизменяемые" структурынет.Нетривиальные структуры (те, для которых можно создать значение, отличное от значения по умолчанию) являются изменяемыми, если и только если они хранятся в изменяемых местах хранения , независимо от любой семантики, навязанной типом.Самоповоротящиеся структуры, то есть структуры, которые изменяют this в любых методах, кроме конструкторов и установщиков свойств, могут иметь некоторые неожиданные поведения, потому что компиляторы не могут запретить вызов других методов, которые будут изменять this в неизменяемой структуре экземпляры .Однако публичное раскрытие структурных полей не представляет такой опасности.Поскольку все поля изменяемого экземпляра нетривиальной структуры по своей природе являются изменяемыми, независимо от любых попыток, которые структура может предпринять, чтобы разрешить мутацию, и все поля неизменяемого экземпляра структуры являются неизменяемыми, даже если они открыты, структуракоторый пытается сделать свои поля «неизменными» - это на самом деле ложь.Ложь, которая иногда может быть полезна (например, если предполагается, что содержимое поля подчиняется определенным инвариантам), но о которой нельзя говорить без какой-либо реальной причины.

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