我知道 C# 中的 3 种参数评估类型:
- 默认值,即按值
- ref,即by-ref
- out,它是 by-ref,但最初被认为是未初始化的并且强制分配
我的教授说 C# 也支持 by-result,他解释为:
- 参数必须与 LHS 兼容
- 创建参数的本地副本并对其进行操作
- 方法体处理成功后,将copy的值写回参数源
我看不出这是如何指代上述任何类型的。
我知道 C# 中的 3 种参数评估类型:
我的教授说 C# 也支持 by-result,他解释为:
- 参数必须与 LHS 兼容
- 创建参数的本地副本并对其进行操作
- 方法体处理成功后,将copy的值写回参数源
我看不出这是如何指代上述任何类型的。
简短的回答 - 不,它没有。
虽然不清楚老师的意思是什么,但可以获得与文本匹配的代码,例如
int i = 1; f(i); //now i is 2
通过使用捕获局部变量的 lambda 表达式。
int i = 1;
Action<int> f = v => i = 2 * v;
f(i);
Console.WriteLine(i); // now i is 2
请注意,i
调用f
是严格“按值”传递的。也可以是f(42)
- 参数对执行结果将更改的变量没有任何影响。
不,不是明确的 C# 语言功能。它不会受到主要的别名问题的困扰,这种问题在语言仅支持传递引用或将指针作为一阶语言功能时很常见。除了lock关键字之外,使线程更容易的语法很少。
C# 中的一条有帮助的规则是它禁止通过引用传递属性,这个问题只能通过按结果调用来解决。值得注意的是,VB.NET 没有这个规则,而是通过自动实现 call-by-result 来解决它。这确实有制造惊喜的诀窍。
它确实发生在位于另一个执行上下文中的 MarshalByRefObject 上。像另一个 AppDomain 或另一台机器。必要时,需要在调用之前跨上下文边界复制ref参数,然后再复制回来。然而,这对程序来说在很大程度上是透明的,不包括需要显式应用 [Out] 属性的怪癖。
我认为您的教授可能指的是方法完成后的普通变量重新分配(即i = DoSomething(i)
),或者可能是导致变量重新分配的运算符,即++
。
为了说明这一点:
class Immutable
{
public readonly int Value;
public Immutable(int value)
{
this.Value = value;
}
public static Immutable operator ++(Immutable obj)
{
return new Immutable(obj.Value + 1);
}
}
现在我们可以执行以下操作:
Immutable a = new Immutable(1);
Immutable originalA = a;
Debug.Assert(a.Value == 1);
Debug.Assert(a == originalA); // Same instance (obviously).
a++;
Debug.Assert(a.Value == 2);
Debug.Assert(a != originalA); // New instance.
这似乎满足所有标准:
Immutable
。obj
在方法主体内重新分配,它不会影响原始位置)。a
一旦操作员完成执行,就会重新分配,并将指向新创建的实例。编辑
虽然这绝对不是答案,因为它不满足任何一点,但我认为值得一提的是,您还可以通过传递指针来获得“by ref”语义,我相信每个人都知道。然而,有些人可能不知道,这也可以使用 来完成TypedReference
,这是 MS C# 中的一种特殊野兽:
void DodgyIncrement()
{
int i = 0;
this.Increment(__makeref(i));
Debug.Assert(i == 1);
}
void Increment(TypedReference i)
{
__refvalue(i, int) += 1;
}