C#属性和ref参数,为什么不加糖?

我只是遇到了这个错误消息,而在C#

属性或索引器不能作为out或refparameter passing

我知道是什么导致了这一点,做了一个快速的解决scheme,创build一个正确的types的本地variables,调用该函数作为out / ref参数,然后将其分配回属性:

 RefFn(ref obj.prop); 

变成

 { var t = obj.prop; RefFn(ref t); obj.prop = t; } 

很明显,如果该属性不支持在当前上下文中获取和设置,则会失败。

为什么C#没有为我做这个?


我可以想到这可能会导致问题的唯一情况是:

  • 穿线
  • 例外

对于线程来说,转换会影响到写入的时间(在函数调用之后),但是我更怀疑任何代码都可能会在中断的时候得不到同情。

例外情况是, 如果函数分配给几个参数之一而不是抛出? 任何微不足道的解决scheme都会导致所有参数或者一些参数不被分配给某些应该有的而有些不应该被分配的参数。 我再次认为这不会被支持使用该语言。


注意:我理解为什么会生成此错误消息的机制。 我在寻找的是为什么C#不会自动实现微不足道的解决方法。

仅供参考,C#4.0 将会类似于这个糖的东西,但是只有在调用互操作方法的时候 – 部分原因在于这种情况下的纯粹倾向。 我没有太多的testing(在CTP中); 我们必须看看它是如何摆脱的…

因为你传递了索引器的结果 ,这实际上是方法调用的结果。 无法保证索引器属性也有一个setter,如果通过ref传递,会导致开发人员认为自己的财产将被设置而没有设置setter被调用时的虚假安全性。

在更技术层面上,ref和out传递给它们的对象的内存地址,并设置一个属性,你必须调用setter,所以不能保证属性实际上会被改变,特别是当属性types是不可改变的。 ref和out不只是在方法返回时设置它的值,它们将实际的内存引用传递给对象本身。

属性只不过是Java风格的getX / setX方法的语法糖。 对于一个方法的“ref”没有太大的意义。 在你的情况下,这将是有道理的,因为你的属性只是扼杀田野。 属性不一定只是存根,因此框架不能允许属性的'ref'。

编辑 :嗯,简单的答案是,一个属性的getter或setter可能包括远远超过只是一个字段读/写的事实使得它不受欢迎,更不用说可能是意想不到的,允许你提出的糖类。 这并不是说我之前并不需要这个function,只是我明白他们为什么不想提供这个function。

您可以使用带ref / out字段,但不能使用属性。 原因是属性实际上只是特殊方法的语法缩写。 编译器实际上将get / set属性转换为相应的get_Xset_X方法,因为CLR没有立即支持属性。

它不会是线程安全的; 如果两个线程同时创build它们自己的属性值的副本并将其作为parameter passing给函数,则只有其中一个线程返回到属性中。

 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,而字段或局部variables为2。

这个代码示例还强调了当要求编译器做含糖的东西时,像匿名方法这样的东西引入的困难。

原因是C#不支持接受通过引用传递的参数的“参数”属性。 有趣的是,CLR确实支持这个function,但是C#没有。

当你将ref / out前置时,意味着你正在传递一个存储在堆中的引用types。

属性是包装方法,而不是variables。

如果你问为什么编译器不能replace属性的getter返回的字段,那是因为getter可以返回一个const或者只读或者文字或者其他不应该被重新初始化或者覆盖的东西。

这个网站似乎有你的工作。 我还没有testing,所以我不能保证它会工作。 该示例似乎使用reflection来访问属性的获取和设置function。 这可能不是一个推荐的方法,但它可能会完成你所要求的。

http://www.codeproject.com/KB/cs/Passing_Properties_byref.aspx