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.
显然,如果属性不支持在当前上下文中获取和设置,则会失败。
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#不会自动实现简单的解决方法。
9 个解决方案
#1
Just for info, C# 4.0 will have something like this 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中);我们必须看看它是如何实现的......
#2
Because you're passing the result of 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.
因为您传递的是索引器的结果,这实际上是方法调用的结果。不能保证索引器属性也有一个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 set the value upon return of the method, they pass the actual memory reference to the object itself.
在更技术层面上,ref和out传递传递给它们的对象的内存地址,并设置属性,你必须调用setter,所以不能保证该属性实际上会被更改,特别是当属性类型是不可改变的。 ref和out不只是在返回方法时设置值,它们将实际的内存引用传递给对象本身。
#3
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可能不仅仅包括一个字段读/写的事实使得它不可取,更不用说可能意外了,允许你提出的那种糖。这并不是说我以前不需要这个功能,只是因为我理解为什么他们不想提供它。
#4
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没有立即支持属性。
#5
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.
该代码示例还强调了在要求编译器执行含糖工作时,匿名方法等问题所引入的困难。
#6
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#不支持。
#7
When you pass ref/out prepended it means that you are passing a reference type which is stored in the heap.
当您传递ref / out prepended时,它意味着您正在传递存储在堆中的引用类型。
Properties are wrapper methods, not variables.
属性是包装器方法,而不是变量。
#8
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或literal或其他不应该重新初始化或覆盖的东西。
#9
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
#1
Just for info, C# 4.0 will have something like this 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中);我们必须看看它是如何实现的......
#2
Because you're passing the result of 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.
因为您传递的是索引器的结果,这实际上是方法调用的结果。不能保证索引器属性也有一个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 set the value upon return of the method, they pass the actual memory reference to the object itself.
在更技术层面上,ref和out传递传递给它们的对象的内存地址,并设置属性,你必须调用setter,所以不能保证该属性实际上会被更改,特别是当属性类型是不可改变的。 ref和out不只是在返回方法时设置值,它们将实际的内存引用传递给对象本身。
#3
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可能不仅仅包括一个字段读/写的事实使得它不可取,更不用说可能意外了,允许你提出的那种糖。这并不是说我以前不需要这个功能,只是因为我理解为什么他们不想提供它。
#4
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没有立即支持属性。
#5
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.
该代码示例还强调了在要求编译器执行含糖工作时,匿名方法等问题所引入的困难。
#6
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#不支持。
#7
When you pass ref/out prepended it means that you are passing a reference type which is stored in the heap.
当您传递ref / out prepended时,它意味着您正在传递存储在堆中的引用类型。
Properties are wrapper methods, not variables.
属性是包装器方法,而不是变量。
#8
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或literal或其他不应该重新初始化或覆盖的东西。
#9
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