【发布时间】:2010-08-06 08:23:47
【问题描述】:
C#:函数中的“输出”参数可以是对象属性/变量吗?
例如:
我可以这样调用函数吗:
someFunction(x, y, out myObject.MyProperty1)
【问题讨论】:
-
编译器是怎么说的?
-
@Frank:如果我知道,我为什么要问这个问题?
标签: c# out-parameters
C#:函数中的“输出”参数可以是对象属性/变量吗?
例如:
我可以这样调用函数吗:
someFunction(x, y, out myObject.MyProperty1)
【问题讨论】:
标签: c# out-parameters
属性是 [一对 get 和 set] 方法,具有用于调用它们的可爱语法,使它们看起来像字段。
Out 参数可以是对字段或基于堆栈的“字段”(即本地变量)的引用。
这种差距的弥合通常不是由语言解决的(当然也不是直接由 CLR 和 IL 模型解决)。 (在@Heinzi 上为 VB 诡计参考 +1)
【讨论】:
ref int i 将隐藏一些相当复杂的代码。 . .但只有当一个属性被传递时。取消引用一个 int 和使用成对的闭包之间的巨大差异。附:没有 cmets,我无法拒绝投票。
out 映射到 & - 这意味着如果没有语言转换所有用法,就无法实现这一点ref 和 int 到你所说的那对代表。 (inishtech.com/FAQ24 是我碰巧思考过这首爵士乐的原因之一!)。我怀疑(没有读过@Heinzi 的引文)这种 VB.NET 的疯狂可能只适用于私人(即使是内部人员也会有很多问题)。顺便说一句,为什么我总是在搏击俱乐部的帖子上撞到你?!
ByRef arg 的属性调用都会将属性值复制到本地,执行调用,然后使用本地更新属性,例如AMethod(myObj.MyProperty) 变为 var temp = myObj.MyProperty; AMethod(ref temp); myObj.MyProperty = temp。这是普通的愚蠢的恕我直言。我添加了一个答案来说明原因。附言因为这些是有趣的线程。
不,您不能在 C# 中将 属性 用作 ref 或 out 参数,因为 CLR 不支持这一点。传递一个实例变量应该可以正常工作。
附带说明,VB.NET 允许传递属性并使用一种称为“复制回 ByRef”的技术,如 this MSDN blog entry 中所述。
【讨论】:
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) 根本不工作
【讨论】:
传递给 out 参数的参数不能是属性。如果你尝试编译你的代码,你会得到一个编译错误。
属性、索引器或动态成员访问不能作为 out 或 ref 参数传递
原因是属性实际上不是字段(它可能有一个支持字段,但也可能没有)。它是两种方法,称为get_Foo 和set_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();
}
}
【讨论】:
您可以将out 参数与字段(或已经说过的本地)一起使用。
【讨论】: