C# 属性和 ref 参数,为什么不加糖?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/529782/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
C# property and ref parameter, why no sugar?
提问by BCS
I just ran across this error message while working in C#
我在 C# 中工作时遇到了这个错误消息
A property or indexer may not be passed as an out or ref parameter
属性或索引器不能作为 out 或 ref 参数传递
I known what caused this and did the quick solution of creating a local variable of the correct type, calling the function with it as the out
/ref
parameter and then assigning it back to the property:
我知道是什么导致了这种情况,并快速解决了创建正确类型的局部变量,使用它作为out
/ref
参数调用函数,然后将其分配回属性的快速解决方案:
RefFn(ref obj.prop);
turns into
变成
{
var t = obj.prop;
RefFn(ref t);
obj.prop = t;
}
Clearly this would fail if the property doesn't support get and set in the current context.
显然,如果该属性在当前上下文中不支持 get 和 set,这将失败。
Why doesn't C# just do that for me?
为什么 C# 不为我做这件事?
The only cases where I can think of where this might cause problems are:
我能想到这可能会导致问题的唯一情况是:
- threading
- exceptions
- 穿线
- 例外
For threading that transformation affects when the writes happen (after the function call vs. in the function call), but I rather suspect any code that counts on that would get little sympathy when it breaks.
对于线程,转换会影响写入发生的时间(在函数调用之后与在函数调用中),但我更怀疑任何依赖于它的代码在中断时几乎不会得到同情。
For exceptions, the concern would be; what happens if the function assigns to one of several ref
parameters than throws? Any trivial solution would result in all or none of the parameters being assigned to when some should be and some should not be. Again I don't think this would be supported use of the language.
对于例外情况,问题是;如果函数分配给几个ref
参数之一而不是 throws 会发生什么?任何微不足道的解决方案都会导致所有或不分配任何参数,而有些应该是,有些则不应该。我再次认为这不会支持使用该语言。
Note: I understand the mechanics of why this error messages is generated. What I'm looking for is the rationale for why C# doesn't automatically implement the trivial workaround.
注意:我了解生成此错误消息的机制。我正在寻找的是为什么 C# 不自动实现微不足道的解决方法的基本原理。
采纳答案by Marc Gravell
Just for info, C# 4.0 willhave something likethis sugar, but only when calling interop methods - partly due to the sheer propensity of ref
in this scenario. I haven't tested it much (in the CTP); we'll have to see how it pans out...
只是为了信息,C#4.0将有一些像这样的糖,但调用的互操作方法,只有当-部分原因是由于纯粹的倾向,ref
在这种情况下。我没有对其进行太多测试(在 CTP 中);我们得看看结果如何……
回答by Brian Rasmussen
You can use fields with ref
/out
, but not properties. The reason is that properties are really just a syntax short cut for special methods. The compiler actually translates get / set properties to corresponding get_X
and set_X
methods as the CLR has no immediate support for properties.
您可以使用带有ref
/ 的字段out
,但不能使用属性。原因是属性实际上只是特殊方法的语法捷径。编译器实际上将 get / set 属性转换为相应的get_X
和set_X
方法,因为 CLR 没有立即支持属性。
回答by David Morton
Because you're passing the resultof the indexer, which is really the result of a method call. There's no guarantee that the indexer property also has a setter, and passing it by ref would lead to a false security on the developer's part when he thinks that his property is going to be set without the setter being called.
因为您正在传递索引器的结果,这实际上是方法调用的结果。不能保证 indexer 属性也有一个 setter,当他认为他的属性将在没有调用 setter 的情况下设置时,通过 ref 传递它会导致开发人员的错误安全。
On a more technical level, ref and out pass the memory address of the object passed into them, and to set a property, you have to call the setter, so there's no guarantee that the property would actually be changed especially when the property type is immutable. ref and out don't just setthe value upon return of the method, they pass the actual memory reference to the object itself.
在更技术层面上,ref 和 out 传递传入它们的对象的内存地址,并且要设置一个属性,您必须调用 setter,因此不能保证该属性实际上会被更改,尤其是当属性类型为不可变的。ref 和 out 不只是在方法返回时设置值,它们将实际内存引用传递给对象本身。
回答by Igor Zelaya
When you pass ref/out prepended it means that you are passing a reference type which is stored in the heap.
当您在前面传递 ref/out 时,这意味着您正在传递存储在堆中的引用类型。
Properties are wrapper methods, not variables.
属性是包装方法,而不是变量。
回答by user7116
Properties are nothing more than syntactic sugar over the Java style getX/setX methods. It doesn't make much sense for 'ref' on a method. In your instance it would make sense because your properties are merely stubbing out fields. Properties don't have to just be stubs, hence the framework cannot allow 'ref' on Properties.
属性只不过是 Java 风格的 getX/setX 方法的语法糖。'ref' 在方法上没有多大意义。在您的实例中,这是有道理的,因为您的属性只是剔除字段。属性不必只是存根,因此框架不允许在属性上使用“ref”。
EDIT: Well, the simple answer is that the mere fact that a Property getter or setter could include far more than just a field read/write makes it undesirable, not to mention possibly unexpected, to allow the sort of sugar you are proposing. This isn't to say I haven't been in need of this functionality before, just that I understand why they wouldn't want to provide it.
编辑:嗯,简单的答案是,属性 getter 或 setter 可能包含的不仅仅是一个字段读/写这一事实使得它不受欢迎,更不用说可能出乎意料的,允许你提议的那种糖。这并不是说我以前不需要这个功能,只是我理解他们为什么不想提供它。
回答by BC.
If you're asking why the compiler doesn't substitute the field returned by the property's getter, it's because the getter can return a const or readonly or literal or something else that shouldn't be re-initialized or overwritten.
如果您要问为什么编译器不替换属性的 getter 返回的字段,那是因为 getter 可以返回 const 或 readonly 或文字或其他不应重新初始化或覆盖的内容。
回答by regex
This site appears to have a work around for you. I have not tested it though, so I can't guarantee it will work. The example appears to use reflection in order to gain access to the get and set functions of the property. This is probably not a recommended approach, but it might accomplish what you're asking for.
该站点似乎为您提供了解决方法。不过我还没有测试过,所以我不能保证它会起作用。该示例似乎使用反射来访问属性的 get 和 set 函数。这可能不是推荐的方法,但它可能会完成您的要求。
http://www.codeproject.com/KB/cs/Passing_Properties_byref.aspx
http://www.codeproject.com/KB/cs/Passing_Properties_byref.aspx
回答by Andrew Hare
The reason for this is that C# does not support "parameterful" properties that accept parameters passed by reference. It is interesting to note that the CLR does support this functionalty but C# does not.
这样做的原因是 C# 不支持接受通过引用传递的参数的“参数化”属性。有趣的是,CLR 确实支持此功能,但 C# 不支持。
回答by Mark Rendle
It wouldn't be thread-safe; if two threads simultaneously create their own copies of the property value and pass them to functions as ref parameters, only one of them ends up back in the property.
它不会是线程安全的;如果两个线程同时创建自己的属性值副本并将它们作为 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 ends up as 1, whereas a field or local variable would be 2.
PropertyX 最终为 1,而字段或局部变量将为 2。
That code sample also highlights the difficulties introduced by things like anonymous methods when asking the compiler to do sugary stuff.
该代码示例还强调了在要求编译器做一些甜言蜜语的事情时匿名方法等引入的困难。