【问题标题】:C#: can 'out' parameters in functions be object properties/variables? [duplicate]C#:函数中的“输出”参数可以是对象属性/变量吗? [复制]
【发布时间】:2010-08-06 08:23:47
【问题描述】:

C#:函数中的“输出”参数可以是对象属性/变量吗?

例如:

我可以这样调用函数吗:

someFunction(x, y, out myObject.MyProperty1)

【问题讨论】:

  • 编译器是怎么说的?
  • @Frank:如果我知道,我为什么要问这个问题?

标签: c# out-parameters


【解决方案1】:

属性是 [一对 get 和 set] 方法,具有用于调用它们的可爱语法,使它们看起来像字段。

Out 参数可以是对字段或基于堆栈的“字段”(即本地变量)的引用。

这种差距的弥合通常不是由语言解决的(当然也不是直接由 CLR 和 IL 模型解决)。 (在@Heinzi 上为 VB 诡计参考 +1)

【讨论】:

  • 将不胜感激 -1 的基本原理(除了 @Mark Byers 的回答自最初发布以来已经发展到包含这个角度的事实?)
  • @Craig Johnston:我赞扬你看穿了答案的迷雾并辩论了你所引发的看似直截了当的问题!
  • +1:为此,您确实需要为每个属性捕获一对闭包。那时ref int i 将隐藏一些相当复杂的代码。 . .但只有当一个属性被传递时。取消引用一个 int 和使用成对的闭包之间的巨大差异。附:没有 cmets,我无法拒绝投票。
  • @Binary Worrier:底线是 CLR 直接支持 IL 级别的引用,out 映射到 & - 这意味着如果没有语言转换所有用法,就无法实现这一点ref 和 int 到你所说的那对代表。 (inishtech.com/FAQ24 是我碰巧思考过这首爵士乐的原因之一!)。我怀疑(没有读过@Heinzi 的引文)这种 VB.NET 的疯狂可能只适用于私人(即使是内部人员也会有很多问题)。顺便说一句,为什么我总是在搏击俱乐部的帖子上撞到你?!
  • 在这里!无论范围如何,您都可以使用 VB.Net 中的任何属性执行此操作。基本上每个对ByRef arg 的属性调用都会将属性值复制到本地,执行调用,然后使用本地更新属性,例如AMethod(myObj.MyProperty) 变为 var temp = myObj.MyProperty; AMethod(ref temp); myObj.MyProperty = temp。这是普通的愚蠢的恕我直言。我添加了一个答案来说明原因。附言因为这些是有趣的线程。
【解决方案2】:

不,您不能在 C# 中将 属性 用作 refout 参数,因为 CLR 不支持这一点。传递一个实例变量应该可以正常工作。

附带说明,VB.NET 允许传递属性并使用一种称为“复制回 ByRef”的技术,如 this MSDN blog entry 中所述。

【讨论】:

  • +1:我强烈建议不要在 VB.Net 中传递属性 byref,这可能会产生令人惊讶的副作用,如果像 C# 一样不受支持则更好。
  • @Binary:你有这个说法的证据/参考吗?
  • @Craig:在下面添加了我自己的“答案”,VB 代码示例说明了我的意思stackoverflow.com/questions/3422078/…
【解决方案3】:

C# 无法做到这一点。
您可以使用 VB.Net,但我认为这是一个坏主意。以下代码和输出显示了它是如何做到的,并说明了为什么我认为这是一个坏主意,以至于我希望 VB.net 也不允许这样做

Public Class MySimpleClass
    Private _privateInt As Integer
    Public PublicInt As Integer

    Public Property PrivateInt() As Integer
        Get
            Return _privateInt
        End Get
        Set(ByVal value As Integer)
            _privateInt = value
        End Set
    End Property

    Public Sub MyNotifier()
        Console.WriteLine("PublicInt {0} : PrivateInt {1} : Values are not the same", PublicInt, PrivateInt)
    End Sub

End Class

现在从 sub main 调用它,像这样

Sub Main()
    Dim sampleClass As New MySimpleClass
    IterateAndUpdate(sampleClass.PrivateInt, sampleClass.PublicInt, AddressOf sampleClass.MyNotifier)

    Console.WriteLine("Private {0} : Public {0} : values are the same ", sampleClass.PrivateInt, sampleClass.PublicInt)
    Console.ReadKey()
End Sub

Sub IterateAndUpdate(ByRef anInt As Integer, ByRef anOtherInt As Integer, ByVal notifier As Action)
    For i As Integer = 1 To 9
        anInt = i
        anOtherInt = i
        notifier()
    Next
End Sub

这个输出

PublicInt 1 : PrivateInt 0 : 值不同
PublicInt 2:PrivateInt 0:值不一样
PublicInt 3:PrivateInt 0:值不一样
PublicInt 4:PrivateInt 0:值不一样
PublicInt 5:PrivateInt 0:值不一样
PublicInt 6:PrivateInt 0:值不一样
PublicInt 7:PrivateInt 0:值不一样
PublicInt 8:PrivateInt 0:值不一样
PublicInt 9:PrivateInt 0:值不一样
Private 9 : Public 9 : 值相同

可以看到PublicInt成员在通过ByRef时立即在sampleClass上更新,把PrivateInt暴露为属性只在IterateAndUpdate方法结束后更新。

因此,您会从完全相同的调用约定中获得明显不同的行为,这取决于您如何实现传递的项目(这在对 IterateAndUpdate 的调用中并不明显。
隐藏错误或对预期行为进行微小更改的可能性足以让我希望这个“功能”不存在。

在我看来,这不能正常工作,因此它应该是
a) 已修复,编译器团队需要付出相当大的努力,并可能引入重大更改

b) 根本不工作

【讨论】:

    【解决方案4】:

    传递给 out 参数的参数不能是属性。如果你尝试编译你的代码,你会得到一个编译错误。

    属性、索引器或动态成员访问不能作为 out 或 ref 参数传递

    原因是属性实际上不是字段(它可能有一个支持字段,但也可能没有)。它是两种方法,称为get_Fooset_Foo。请参阅c# property and ref parameter, why no sugar? 了解更多关于为什么这不起作用的说明。

    给出编译错误的示例代码:

    class Program
    {
        public int Foo { get; set; }
        public void Bar(out int x)
        {
            x = 5;
        }
        void Run()
        {
            Bar(out Foo); // compile error 
        }
        static void Main()
        {
            new Program().Run();
        }
    }
    

    【讨论】:

      【解决方案5】:

      您可以将out 参数与字段(或已经说过的本地)一起使用。

      【讨论】:

        猜你喜欢
        • 2010-09-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-11-24
        • 2012-11-28
        • 2011-10-13
        • 1970-01-01
        相关资源
        最近更新 更多