Свойство 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# автоматически не реализует тривиальный обходной путь.

773   9  

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

    Ничего не найдено.