В .net метод экземпляра структуры семантически эквивалентен методу статической структуры с дополнительным параметром ref
типа структуры. Таким образом, с учетом деклараций:
struct Blah {
public int value;
public void Add(int Amount) { value += Amount; }
public static void Add(ref Blah it; int Amount; it.value += Amount;}
}
Метод вызывает:
someBlah.Add(5);
Blah.Add(ref someBlah, 5);
семантически эквивалентны, за исключением одного различия: последний вызов будет разрешен только в том случае, если someBlah
- это изменяемое место хранения (переменная, поле и т. Д.), А не если это хранилище только для чтения или временное значение (результат чтения свойства и т. д.).
Это поставило перед разработчиками языков .net проблему: запрет на использование каких-либо функций-членов в структурах только для чтения был бы раздражающим, но они не хотели, чтобы функции-члены могли записывать переменные только для чтения. Они решили «разбить» и сделать так, чтобы при вызове метода экземпляра в структуре, доступной только для чтения, была сделана копия структуры, вызвана функция для этого, а затем отброшена. Это приводит к замедлению вызовов методов экземпляров, которые не пишут базовую структуру, и делает это так, что попытка использовать метод, который обновляет базовую структуру в структуре только для чтения, приведет к различной нарушенной семантике из того, что было бы достигнуто, если бы была передана структура напрямую. Обратите внимание, что дополнительное время, затрачиваемое копией, почти никогда не приведет к правильной семантике в случаях, которые были бы неправильными без копии.
Одним из моих главных недостатков в .net является то, что до сих пор (по крайней мере, 4.0, и, вероятно, 4.5) по-прежнему нет атрибута, через который функция-член структуры может указывать, изменяет ли она this
. Люди ругаются о том, как структуры должны быть неизменными, вместо того, чтобы предоставлять инструменты, позволяющие структурам безопасно предлагать методы мутации. И это несмотря на то, что так называемые «неизменные» структуры являются ложью . Все нетривиальные типы значений в изменяемых местах хранения являются изменяемыми, как и все типы значений в штучной упаковке. Создание структуры «неизменяемой» может вынудить переписать всю структуру, когда нужно изменить только одно поле, но, поскольку struct1 = struct2
изменяет структуру struct1, копируя все открытые и частные поля из struct2, и в этом нет ничего определение типа для структуры может сделать, чтобы предотвратить (кроме отсутствия полей), что она ничего не делает, чтобы предотвратить неожиданную мутацию членов структуры. Кроме того, из-за проблем с многопоточностью структуры очень ограничены в своих возможностях применять любые инвариантные отношения между своими полями. ИМХО, как правило, для структуры было бы лучше разрешить произвольный доступ к полям, давая понять, что любой код, получающий структуру, должен проверять, соответствуют ли ее поля всем необходимым условиям, чем пытаться предотвратить формирование структур, которые не удовлетворяют условиям.