Свойство C# и параметр ref, почему нет сахара?
Я просто наткнулся на это сообщение об ошибке во время работы в C#
свойство или индексатор не могут быть переданы в качестве параметра out или ref
Я знал, что вызвало это и сделал быстрое решение создания локальной переменной правильного типа, вызывая функцию с ней как out/ref параметр и затем присвоение его обратно свойству:
RefFn(ref obj.prop);
превращается в
{
var t = obj.prop;
RefFn(ref t);
obj.prop = t;
}
очевидно, что это не удастся, если свойство не поддерживает get и set в текущем контексте.
почему C# просто не делает это для меня?
единственные случаи, когда я могу думать о том, где это может вызвать проблемы:
- резьбонарезной
- исключения
для потоковой передачи это преобразование влияет на то, когда происходит запись (после вызова функции против вызова функции), но я скорее подозреваю, что любой код, который рассчитывает на это, получит мало сочувствие, когда оно ломается.
для исключений, проблема будет; что произойдет, если функция присваивает один из нескольких ref параметры не бросает? Любое тривиальное решение приведет к тому, что все или ни один из параметров будет назначен, когда некоторые должны быть, а некоторые не должны быть. Опять же, я не думаю, что это будет поддерживаться использование языка.
примечание: Я понимаю механику, почему это сообщение об ошибке генерируется. Что я ищу-это обоснование того, почему C# автоматически не реализует тривиальный обходной путь.
9 ответов:
просто для информации, C# 4.0 будет что-то как это сахар, но только при вызове методов взаимодействия-отчасти из-за явной склонности
refв этом случае. Я не тестировал его много (в CTP); нам нужно будет посмотреть, как это получится...
потому что вы проходите результат индексатора, который на самом деле является результатом вызова метода. Нет никакой гарантии, что свойство индексатора также имеет сеттер, и передача его по ссылке приведет к ложной безопасности со стороны разработчика, когда он думает, что его свойство будет установлено без вызова сеттера.
на более техническом уровне, ref и out передать адрес памяти объекта, переданного в них, чтобы установить свойство, вы должны вызовите сеттер, поэтому нет никакой гарантии, что свойство действительно будет изменено, особенно когда тип свойства является неизменяемым. ref и out не просто set значение при возврате метода они передают фактическую ссылку памяти на сам объект.
свойства-это не что иное, как синтаксический сахар над методами getX/setX стиля Java. Это не имеет большого смысла для " ref " на методе. В вашем случае это имело бы смысл, потому что ваши свойства просто заглушают поля. Свойства не должны быть просто заглушками, поэтому фреймворк не может разрешить " ref " для свойств.
EDIT: Ну, простой ответ заключается в том, что простой факт, что свойство геттер или сеттер может включать в себя гораздо больше, чем просто поле чтение / запись делает его нежелательным, не говоря уже о том, возможно, неожиданным, чтобы позволить вид сахара, который вы предлагаете. Это не значит, что я не нуждался в этой функциональности раньше, просто я понимаю, почему они не хотели бы ее предоставлять.
вы можете использовать поля с
ref/out, но не свойства. Причина в том, что свойства на самом деле просто синтаксис короткий путь для специальных методов. Компилятор на самом деле переводится получить / установить свойства для соответствующегоget_Xиset_Xметоды, поскольку среда CLR не имеет непосредственной поддержки свойств.
это не было бы потокобезопасным; если два потока одновременно создают свои собственные копии значения свойства и передают их в функции в качестве параметров ref, только один из них возвращается в свойство.
class Program { static int PropertyX { get; set; } static void Main() { PropertyX = 0; // Sugared from: // WaitCallback w = (o) => WaitAndIncrement(500, ref PropertyX); WaitCallback w = (o) => { int x1 = PropertyX; WaitAndIncrement(500, ref x1); PropertyX = x1; }; // end sugar ThreadPool.QueueUserWorkItem(w); // Sugared from: // WaitAndIncrement(1000, ref PropertyX); int x2 = PropertyX; WaitAndIncrement(1000, ref x2); PropertyX = x2; // end sugar Console.WriteLine(PropertyX); } static void WaitAndIncrement(int wait, ref int i) { Thread.Sleep(wait); i++; } }PropertyX заканчивается как 1, тогда как поле или локальная переменная будет 2.
этот пример кода также подчеркивает трудности, связанные с такими вещами, как анонимные методы, когда компилятор просит делать сладкие вещи.
причина этого заключается в том, что C# не поддерживает свойства "parameterful", которые принимают параметры, переданные по ссылке. Интересно отметить, что среда CLR поддерживает эту функцию, но C# - нет.
когда вы передаете ref / out, это означает, что вы передаете ссылочный тип, который хранится в куче.
свойства-это методы оболочки, а не переменные.
Если вы спрашиваете, почему компилятор не заменяет поле, возвращаемое геттером свойства, это потому, что геттер может возвращать const или readonly или literal или что-то еще, что не должно быть повторно инициализировано или перезаписано.
У этого сайта, похоже, есть работа для вас. Я не проверял его, Хотя, поэтому я не могу гарантировать, что он будет работать. В примере используется отражение для получения доступа к функциям get и set свойства. Это, вероятно, не рекомендуется подход, но он может выполнить то, что вы просите.
http://www.codeproject.com/KB/cs/Passing_Properties_byref.aspx
Comments