Кто-то может сказать мне, почему прокомментированная строка кода (один прежде в последний раз) не компилирует? Разве это не то же как строка после него?
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);
}
}
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.
Извиняюсь за то, что не использовал комментарий, я не думаю, что он подойдет. Джон, это не настоящая реализация, я просто пытаюсь получить более глубокое понимание структур, поэтому не беспокойтесь о том, что я реализую изменяемые структуры :)
В любом случае, я не уверен, что вы правы . Рассмотрим этот код, он почти такой же, как и в первом примере:
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);
И поэтому мне кажется, что первая строка не компилируется просто потому, что компилятор не поддерживает его не потому, что это незаконно.
Как вы думаете?