当前位置:  开发笔记 > 编程语言 > 正文

是否可以将属性作为"out"或"ref"参数传递?

如何解决《是否可以将属性作为"out"或"ref"参数传递?》经验,为你挑选了2个好方法。

我可以将属性作为"out"或"ref"参数传递,如果不是,为什么不呢?

例如

Person p = new Person(); 

...

public void Test(out p.Name);

Binary Worri.. 38

对于简短的回答道歉,但不是,C#语言规范不允许这样做.

看到另一个问题的答案,看看你尝试时会发生什么.它还说明了为什么你不应该让这个属性成为一个公共领域来绕过限制.

希望这可以帮助

编辑:你问为什么?

你传递一个变量到一个outref参数,您实际上是在传递地址(或内存位置)的变量.在函数内部,编译器知道变量的确实位置,并获取和写入该地址的值.

属性看起来像一个值,但它实际上是一对函数,每个函数都有不同的签名.所以要传递一个属性,你实际上需要传递两个函数指针,一个用于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,由ref).如果是属性,你如何获得地址i?在该属性下可能没有实际的int来获取地址.你做VB.Net的工作吗?

当属性作为ByRef参数传递给方法时,Vb.Net编译器会发现.此时它声明一个变量,将属性复制到变量,传递变量byref,然后在调用该方法之后,将变量复制回属性.即

MyFunc(myObject.IntProperty)

Dim temp_i As Integer = myObject.IntProperty
MyFunc(temp_i)
myObject.IntProperty = temp_i

任何财产副作用都不会发生,直到MyFunc返回,这可能会导致各种问题并导致非常微妙的错误.

在我看来,这个问题的Vb.Net解决方案也被打破了,所以我不会接受这个作为答案.

您认为C#编译器应如何处理?



1> Binary Worri..:

对于简短的回答道歉,但不是,C#语言规范不允许这样做.

看到另一个问题的答案,看看你尝试时会发生什么.它还说明了为什么你不应该让这个属性成为一个公共领域来绕过限制.

希望这可以帮助

编辑:你问为什么?

你传递一个变量到一个outref参数,您实际上是在传递地址(或内存位置)的变量.在函数内部,编译器知道变量的确实位置,并获取和写入该地址的值.

属性看起来像一个值,但它实际上是一对函数,每个函数都有不同的签名.所以要传递一个属性,你实际上需要传递两个函数指针,一个用于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,由ref).如果是属性,你如何获得地址i?在该属性下可能没有实际的int来获取地址.你做VB.Net的工作吗?

当属性作为ByRef参数传递给方法时,Vb.Net编译器会发现.此时它声明一个变量,将属性复制到变量,传递变量byref,然后在调用该方法之后,将变量复制回属性.即

MyFunc(myObject.IntProperty)

Dim temp_i As Integer = myObject.IntProperty
MyFunc(temp_i)
myObject.IntProperty = temp_i

任何财产副作用都不会发生,直到MyFunc返回,这可能会导致各种问题并导致非常微妙的错误.

在我看来,这个问题的Vb.Net解决方案也被打破了,所以我不会接受这个作为答案.

您认为C#编译器应如何处理?


这已破了.C#不是低级语言,所以`ref`参数不应该是一个地址,而是一对闭包,一个getter和一个setter.如果将局部变量作为`ref`参数传递,则该语言应自动创建一个getter/setter对.所有这一切都应该从毫无戒心的程序员那里隐藏起来.
@supercat虽然更简单的增强功能是让你在自动属性上使用ref.编译器生成它们的后备字段,因此它可以仅在后备字段上进行ref工作.

2> Jon Skeet..:

其他人解释说你不能用C#做到这一点.在VB.NET中,即使使用选项strict/explicit ,也可以执行此操作:

Option Strict On
Option Explicit On
Imports System.Text

Module Test

   Sub Main()
       Dim sb as new StringBuilder
       Foo (sb.Length)
   End Sub

   Sub Foo(ByRef x as Integer)
   End Sub

End Module

上面的代码相当于这个C#代码:

using System.Text;

class Test
{
     static void Main()
     {
         StringBuilder sb = new StringBuilder();
         int tmp = sb.Length;
         Foo(ref tmp);
         sb.Length = tmp;
     }

     static void Foo(ref int x)
     {
     }
}

就我个人而言,我很高兴C#没有这个 - 它在水域中非常混乱,特别是在属性值方面,如果参数在方法中设置但随后抛出异常.

编辑:根据要求,我的理由为什么我相信在泥泞的水域传递属性.如果通过引用传递正常变量,则每次在方法中引用该变量时都会对该变量进行求值.如果值由于某种原因而发生变化(例如,作为方法中某些其他工作的副作用),那么该变化将立即在方法中可见.如果您在VB.NET中通过引用传递属性,则不是这种情况:属性getter被调用一次,然后属性setter被调用一次.这并不像你传入的"这是一个属性 - 每当你使用参数时都可以从中获取和设置."

这是一个完整的例子,在.NET中传递一个字段并传递一个完全无关的属性会产生非常不同的结果:

Option Strict On
Option Explicit On
Imports System.Text

Class Test

   Dim counter as Integer

   Property CounterProperty As Integer
       Get
           Return counter
       End Get
       Set (ByVal value as Integer)
           counter = value
       End Set
   End Property

   Sub Increment
       counter += 1
   End Sub

   Shared Sub Main()
       Dim t as new Test()
       Console.WriteLine("Counter = {0}", t.counter)
       t.Foo(t.counter)
       Console.WriteLine("Counter = {0}", t.counter)

       t.CounterProperty = 0
       Console.WriteLine("CounterProperty = {0}", t.CounterProperty)
       t.Foo(t.CounterProperty)
       Console.WriteLine("CounterProperty = {0}", t.CounterProperty)
   End Sub

   Sub Foo(ByRef x as Integer)
       x = 5
       Increment
       Increment
       Increment
       x += 1
   End Sub

End Class


乔恩:如果你不介意,你能否阐明你对"混淆水域"的想法,我不明白为什么你认为将属性传递给参数是一个特别糟糕的想法(我不是说他们是一个好主意).谢了哥们.
推荐阅读
php
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有