Сегодня столкнулся с любобытнейшим багом в C#. Вполне возможно, что это не баг, а предусмотренное поведение, но выглядит оно необычно.
В двух словах: readonly переменная изменяема только в конструкторе класса и даже если конструктор вызовет метод, изменяющий ее - эти изменения будут отброшены.
Рассмотрим такой код с вспомогательной структурой и классом.
public struct TestStruct
{
private int m_count;
private int m_value;
public int Count
{
get { return m_count; }
}
public int Value
{
get { return m_value; }
}
public TestStruct(int value)
{
m_value = value;
m_count = 0;
}
public void Increment()
{
m_count++;
}
}
public class TestClass
{
private TestStruct m_struct;
public int Value
{
get { return m_struct.Value; }
}
public int Count
{
get { return m_struct.Count; }
}
public TestClass(int value)
{
m_struct = new TestStruct(value);
for (int i = 0; i < value; i++)
Increment();
}
private void Increment()
{
m_struct.Increment();
}
}
Если создать экземпляр TestClass с каким-либо числом, то значения Value и Count будут равны этому числу. Вполне нормальное и логичное поведение.
Картина меняется, если мы добавим слово readonly:
private readonly TestStruct m_struct;
После этого изменения код
TestClass test = new TestClass(11);
Console.WriteLine("Test result: value {0}, count {1}",
test.Value, test.Count);
выдает такой результат:
Test result: value 11, count 0
Верно такое поведение или нет?
Мы знаем, что структуры являются value-type и для каждого члена структуры, вложенной в класс, память выделяется в самом классе. Потому логично предположить, что readonly распостраняется и на члены структуры. Неприятно, но компилятор нам об этом не сообщает и никак не предупреждает, что этот модификатор приведет к потере данных.
Более того, логично было бы предположить, что если метод Increment() обьявлен как private и используется только в конструкторе, то метод будет inline и на него будут распостранятся те же правила, что и для конструктора. К сожалению, это предположение не оправдывается и нам просто надо помнить, что вызов методов в конструкторе может привести к "необычным" последствиям, не говоря о том, что может быть при вызове виртуальных методов.
0 коммент.:
Отправить комментарий