Изменение вложенных структур в c#

Кто-то может сказать мне, почему прокомментированная строка кода (один прежде в последний раз) не компилирует? Разве это не то же как строка после него?

public struct OtherStruct
{
    public int PublicProperty { get; set; }
    public int PublicField;

    public OtherStruct(int propertyValue, int fieldValue)
        : this()
    {
        PublicProperty = propertyValue;
        PublicField = fieldValue;
    }

    public int GetProperty()
    {
        return PublicProperty;
    }
    public void SetProperty(int value)
    {
        PublicProperty = value;
    }
}

public struct SomeStruct
{
    public OtherStruct OtherStruct { get; set; }
}

class Program
{
    static void Main(string[] args)
    {
        SomeStruct a = new SomeStruct();
        //a.OtherStruct.PublicProperty++;
        a.OtherStruct.SetProperty(a.OtherStruct.GetProperty() + 1);
    }
}
5
задан joniba 12 April 2010 в 16:44
поделиться

2 ответа

SomeStruct.OtherStruct - это свойство, возвращающее значение, а не переменная. Эта строка:

a.OtherStruct.PublicProperty++;

похожа на вызов:

a.get_OtherStruct().PublicProperty++;

Поскольку выражение a.get_OtherStruct () представляет собой значение , а не переменную , это немного как это сделать:

OtherStruct tmp = a.get_OtherStruct();
tmp.PublicProperty++;

Изменение значения PublicProperty в копии из OtherStruct , возвращаемой свойством, вообще не изменит исходное значение . Это почти наверняка не ваше намерение. Разработчики C # предвидели подобную проблему и во многих ситуациях умудрялись ее запретить.

Обратите внимание, что если бы OtherStruct был ссылочным типом (классом) вместо этого, то была бы скопирована ссылка ссылка , а не значения в нем ... поэтому изменение tmp.PublicProperty будет иметь значение. См. Мою статью о ссылочных типах и типах значений для получения дополнительной информации.

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

РЕДАКТИРОВАТЬ: В ответ на ваш «ответ» две строки не одинаковы: выражение свойства a.OtherStruct не является целью оператора присваивания или составной оператор присваивания.

Вы можете возразить, что хотите, чтобы C # был определен таким образом, чтобы это позволяло (хотя я все равно не согласен), но компилятор правильно реализует спецификацию. Дополнительные сведения см. В разделе 10.7.2 спецификации C # 3.0.

10
ответ дан 13 December 2019 в 19:24
поделиться

Извиняюсь за то, что не использовал комментарий, я не думаю, что он подойдет. Джон, это не настоящая реализация, я просто пытаюсь получить более глубокое понимание структур, поэтому не беспокойтесь о том, что я реализую изменяемые структуры :)

В любом случае, я не уверен, что вы правы . Рассмотрим этот код, он почти такой же, как и в первом примере:

public struct SomeStruct
{
    public int PublicProperty { get; set; }
    public int PublicField;

    public SomeStruct(int propertyValue, int fieldValue)
        : this()
    {
        PublicProperty = propertyValue;
        PublicField = fieldValue;
    }

    public int GetProperty()
    {
        return PublicProperty;
    }
    public void SetProperty(int value)
    {
        PublicProperty = value;
    }
}

class Program
{
    static void Main(string[] args)
    {
        SomeStruct a = new SomeStruct(1, 1);
        a.PublicProperty++;
        a.SetProperty(a.GetProperty()+1);
    }
}

Теперь, глядя на msil с помощью ildasm, я получаю следующее для метода Main:

.method private hidebysig static void Main (string [] args) cil управляемый

{

.entrypoint

// Code size       45 (0x2d)

.maxstack  3

.locals init ([0] valuetype ConsoleApplication1.SomeStruct a)

IL_0000:  nop

IL_0001:  ldloca.s   a

IL_0003:  ldc.i4.1

IL_0004:  ldc.i4.1

IL_0005:  call       instance void ConsoleApplication1.SomeStruct::.ctor(int32,
                                                                         int32)
IL_000a:  nop

IL_000b:  ldloca.s   a

IL_000d:  dup

IL_000e:  call       instance int32 

ConsoleApplication1.SomeStruct :: get_PublicProperty ()

IL_0013:  ldc.i4.1

IL_0014:  add

IL_0015:  call       instance void 

ConsoleApplication1.SomeStruct :: set_PublicProperty (int32)

IL_001a:  nop

IL_001b:  ldloca.s   a

IL_001d:  ldloca.s   a

IL_001f:  call       instance int32 ConsoleApplication1.SomeStruct::GetProperty()

IL_0024:  ldc.i4.1

IL_0025:  add

IL_0026:  call       instance void ConsoleApplication1.SomeStruct::SetProperty(int32)

IL_002b:  nop

IL_002c:  ret

}

Прошу прощения за ужасное форматирование, я не знаю, как сделать это нормально выглядит. В любом случае, надеюсь, вы видите, что последние 2 строки кода в основном методе фактически идентичны.

Следовательно, я бы сказал, что из предыдущего поста эта строка:

a.OtherStruct.PublicProperty++;

на самом деле идентична строке после нее:

 a.OtherStruct.SetProperty(a.OtherStruct.GetProperty() + 1);

И поэтому мне кажется, что первая строка не компилируется просто потому, что компилятор не поддерживает его не потому, что это незаконно.

Как вы думаете?

1
ответ дан 13 December 2019 в 19:24
поделиться
Другие вопросы по тегам:

Похожие вопросы: