是否可以将属性作为“out”传递? 或“参考” 参数?
我可以将属性作为“out”或“ref”参数传递吗?如果不能,那为什么不呢?
例如
Person p = new Person();
。 。 。
public void Test(out p.Name);
Can I pass a property as an "out" or "ref" parameter if not then why not?
e.g.
Person p = new Person();
.
.
.
public void Test(out p.Name);
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
对于简短的回答,我们深表歉意,但不行,C# 语言规范不允许这样做。
请参阅此答案 到另一个问题看看当你尝试时会发生什么。
它还说明了为什么您不应该将财产仅仅作为公共场所来规避限制。
希望这会有所帮助
编辑:你问为什么?
你将一个变量传递给你实际传递的地址(或位置)的
out
或ref
参数在内存中)的变量。在函数内部,编译器知道变量的实际位置,并获取值并将值写入该地址。
属性看起来像一个值,但它实际上是一对函数,每个函数都有不同的签名。 因此,要传递属性,实际上需要传递两个函数指针,一个用于 get,一个用于 set。
传递给函数与变量的地址
(即一个变量地址 v 的两个函数指针)是完全不同的。
更新
为什么 C# 不帮我们处理这个问题?
我不是 Eric Lippert,但我会尝试一下为什么
您调用的函数的签名应该是什么?
假设您想调用
void MyFn(ref int i)
应该保持这种方式,还是应该更改为我们也允许属性? 如果它更改为像void MyFn(prop_ref int i)
这样的语法,那么这是相当无用的,您无法将属性传递给不是使用特殊 prop_ref 修饰符编写的库函数或第三方代码。 无论如何,我认为你建议它不应该有所不同。现在假设
MyFn
将i
传递给 COM 函数或 WinAPI 调用,传递i
的地址(即在 .net 外部,通过引用) 。 如果是属性,如何获取i
的地址? 该属性下可能没有实际的 int 来获取其地址。 你做VB.Net做的事吗?Vb.Net 编译器会发现属性何时作为 ByRef 参数传递给方法。 此时它声明一个变量,将属性复制到该变量,通过引用传递变量,然后在调用该方法后,将变量复制回属性。 即
,
在
MyFunc
返回之前,任何属性副作用都不会发生,这可能会导致各种问题并导致非常微妙的错误。以我的拙见,Vb.Net 对这个问题的解决方案也被破坏了,所以我不会接受这个答案。
您认为 C# 编译器应该如何处理这个问题?
Apologies for the short answer, but no, the C# language specification disallows it.
See this answer to another question to see what happens when you try.
It also says why you shouldn't make the property just be a public field to get around the restriction.
Hope this helps
EDIT: You ask Why?
You pass a variable to an
out
orref
parameter you're actually passing the address (or location in memory) of the variable.Inside the function the compiler knows where the variable really is, and gets and writes values to that address.
A property looks like a value, buts it's actually a pair of functions, each with a different signature. So to pass a property, you'd actually need to pass two function pointers, one for the get, and one for the set.
Thats a completely different thing to pass to a function than the address of a variable
i.e. one variable address v's two function pointers.
Update
Why doesn't C# just look after this for us?
I'm no Eric Lippert, but I'll have a go at why
What should the signature of the function you're calling be?
Lets say you want to call
void MyFn(ref int i)
should that remain that way, or should it change to say we also allow properties? If it changes to some syntax likevoid MyFn(prop_ref int i)
then this is fairly useless, you can't pass properties to library functions or 3rd party code that wasn't written with the special prop_ref modifier. Anyway I think you're suggesting it shouldn't be different.Now lets say
MyFn
passesi
to a COM function, or WinAPI call, passing the address ofi
(i.e. outside .net, by ref). If it's a property, how do you get the address ofi
? There may be no actual int under the property to get the address of. Do you do what VB.Net does?The Vb.Net compiler spots when a property is passed as a ByRef argument to a method. At that point it declares a variable, copies the property to the variable, passes the variable byref and then after the method is called, copies the variable back into the property. i.e.
becomes
Any property side effects don't happen until
MyFunc
returns, which can cause all sorts of problems and lead to very subtle bugs.In my humble opinion the Vb.Net solution to this problem is also broken, so I'm not going to accept that as an answer.
How do you think the C# compiler should handle this?
其他人已经解释说你不能在 C# 中执行此操作。 在 VB.NET 中,您可以执行此操作,即使启用了 strict/explicit 选项:
上面的代码相当于此 C# 代码:
就我个人而言,我很高兴 C# 没有此功能 - 它很混乱水域相当多,特别是在属性值方面,如果在方法内设置参数,但随后抛出异常。
编辑:根据要求,我对为什么我相信传递财产会使水变得浑浊的推理。 如果通过引用传递普通变量,则每次在方法中引用该变量时都会计算该变量。 如果该值由于某种原因发生变化(例如,作为方法中某些其他工作的副作用),则该更改将立即在方法中可见。 如果在 VB.NET 中通过引用传递属性,则情况并非如此:属性 getter 被调用一次,然后属性 setter 被调用一次。 这并不像您传递“这是一个属性 - 每当您使用参数时都可以从中获取和设置”。
下面是一个完整的示例,其中在 .NET 中传递字段和传递完全微不足道的属性会产生截然不同的结果:
.Net-Fiddle: https ://dotnetfiddle.net/ZPFIEZ(字段和属性的不同结果)
Others have explained that you can't do this in C#. In VB.NET, you can do this, even with option strict/explicit on:
The above code is equivalent to this C# code:
Personally I'm glad that C# doesn't have this - it's muddying the waters quite a lot, particularly in terms of the value of the property if the parameter is set within the method but then an exception is thrown.
EDIT: As requested, my reasoning as to why I believe passing properties in muddies the waters. If you pass a normal variable by reference, then that variable is evaluated every time it is referenced within the method. If the value changes for some reason (e.g. as a side-effect of some other work in the method) then that change will be immediately visible in the method. That's not the case if you pass a property by reference in VB.NET: the property getter is invoked once, and then the property setter is invoked once. It's not like you're passing in "here's a property - get and set from that whenever you use the parameter."
Here's a full example where passing a field and passing an entirely trivial property in .NET have very different results:
.Net-Fiddle: https://dotnetfiddle.net/ZPFIEZ (different results for field and property)
相反,你应该做这样的事情
Instead, you should do something like this