在方法中修改方法参数或返回结果

Modify method parameter within method or return result

提问人:JMS 提问时间:2/17/2009 最后编辑:one noaJMS 更新时间:11/15/2023 访问量:70786

问:

两者之间有什么区别

private void DoSomething(int value) {
    value++;
}

private int DoSomething(int value) {
   return value++;
}

当用作

DoSomething(value);

value = DoSomething(value);
C# .NET 参数传递

评论

9赞 Wedge 2/17/2009
仅供参考,您列出的两个函数都不正确。“return value++;” 将仅返回值,您需要 “return value+1;” 或 “return ++value;”,并且输入值只是传递给函数的变量的副本,除非您使用 “ref” 关键字将其指定为引用参数。
0赞 JMS 2/17/2009
这是我问题的一个过于简单的例子,但无论如何感谢您指出这一点。我的代码中有问题的方法是操作字典和字符串。

答:

73赞 Rex M 2/17/2009 #1

您正在谈论按引用传递和按值传递之间的区别,这在概念上类似于类型与引用类型的概念。

如果将值类型传递到方法中,则必须使用第二个示例;否则,您只是递增存在于 DoSomething() 范围内的整数。尝试一下:如果你执行你的第一个例子,在 DoSomething() 运行后,你的 int 的值将保持不变。

但是,如果传入的不是值类型(例如对象 foo),则实际上是在传递对原始对象的引用。你在 DoSomething() 中对它所做的任何事情也会在方法之外生效,因为你仍然引用同一个对象。

您可以通过编写以下内容来完成您在第一个示例中尝试的操作:

void DoSomething(ref int value)

这将指示 .NET 传递对项的引用,而不管它是否是值类型。

有关更详细的了解,请参阅 MSDN 上有关值类型与引用类型的文章。

此外,正如 zodoz 指出的那样(适当地投赞成票),通过返回,您正在返回然后递增。若要返回递增的值,请使用 。value++++value

评论

5赞 ShuggyCoUk 2/17/2009
请记住,在“参数引用引用类型”的情况下,您正在做的是传递引用的。它仍然是按值传递的。添加 ref 使其真正通过引用传递(因此,它不是传递值的副本,而是将被调用的函数“指向”实际值。
-3赞 iopener 2/17/2009 #2

对于大多数编程语言,您需要通过引用传递参数来更改 void 函数。函数通常不能更改其参数的值;相反,它会创建参数的副本并改用该副本。

为了使用实际变量,您必须更改函数标头以接受对变量的引用,前面的 &) 号如下所示:

private void DoSomething(int &value)

希望对您有所帮助!

评论

0赞 Ray 2/17/2009
C# 使用 out 关键字,而不是 &。
1赞 lc. 2/17/2009
实际上,在这种情况下,您会想使用 ref,而不是 out。
1赞 iopener 2/17/2009
好家伙,我是新来的,没有看到 C# 标签。对我来说,它看起来很不错 C++。
0赞 Петър Петров 2/14/2017
好吧,你确实可以做到: - 但不要,真的!这只会帮助本机代码互操作。private unsafe void DoSomething(int* value)
1赞 Christian C. Salvadó 2/17/2009 #3

在第一个示例中,int 参数递增,但在方法结束时被销毁,除非使用 refout 关键字,否则无法获取方法外部的值。value

例如:

private int DoSomething(ref int value) {
   return value++;
}

// ...
int myValue = 5;
DoSomething(ref myValue);
// Now myValue is 6.

Ref 和 out 参数传递模式用于允许方法更改方法调用方传入的变量。ref 和 out 之间的主要区别可能很微妙,但很重要。

每种参数传递模式都旨在满足不同的编程需求。

在调用之前,采用 out 参数的方法的调用方不需要分配给作为 out 参数传递的变量;但是,在返回之前,需要将该方法分配给 out 参数。

考虑参数的一种方法是,它们类似于方法的附加返回值。当方法应返回多个值时,它们很方便。

ref 参数导致通过引用传递参数。其效果是,当控制权传递回调用方法时,对方法中参数的任何更改都将反映在该变量中。

不要将引用传递的概念与引用类型的概念混淆

这两个概念不相关;一个方法参数可以被 ref 修改,不管它是值类型还是引用类型,一个值类型在通过引用传递时没有装箱。

4赞 Ray 2/17/2009 #4

简单地说,第一个是行不通的,因为你正在对价值的副本进行操作。

你可以做这样的事情

private int DoSomething(ref int value)
{
  value++;
}

并称它为

DoSomething(ref value);

这将更改要通过引用传入的值。但实际上,这样做的唯一原因是,如果你想从函数中返回多个东西。通常有更好的方法。

对于额外的奖励知识,还有一个类似于 ref 的 out 关键字,但不需要先初始化值。

6赞 Mike 2/17/2009 #5

其他人似乎都在暗示变量传递的差异,但我注意到了一些不同的东西:

如果您显示的示例代码是您正在查看的内容的简化,那么您可能需要在第二个示例中注意:

private int DoSomething(int value) {
    return value++;
}

将返回然后递增。因此,如果您执行以下操作:value

public Main() {
    int val = 1;
    Console.writeln(DoSomething(val));
}

您的输出将是 。1

让我知道这是否有帮助。

41赞 Wedge 2/17/2009 #6

返回一个值。

为什么?

正确性、可读性和自文档

有意且易于理解的代码比副作用代码更好。考虑:

float area = pi * Square(r);

HSP的

Square(r);
float area = pi * r;
// ... intervening code
float x = r * 5;  // did you mean to use the original r or r-squared here?

还要考虑第一个示例中通过可组合性实现简洁性的优势。

考虑方法本身,比较:

int DoSomething(int value)
   { return value+1; }

这显然是正确的。HSP的

void DoSomething(int value)
   { value++; }

这似乎是正确的,并且编译得很好,但实际上只是一个不操作。你真正想要的是这个:

void DoSomething(ref int value)
   { value++; }

// client code:
DoSomething(ref a);

变量很便宜

许多命名良好的变量比少数重用的通用变量更可取。抵制过早优化的诱惑,您需要减少局部变量的数量以提高系统性能的机会微乎其微。同样,变量很便宜,不要重用变量!

测试

考虑:

Assert.IsTrue(Square(2) == 4);

HSP的

float a = 2;
Square(a);
Assert.IsTrue(a == 4);

与返回值相比,避免突变还有许多其他优点。数学将函数定义为输入值到输出值的映射,这不仅仅是偶然的。

评论

0赞 BornToCode 1/18/2021
所有这些是否也适用于私有方法?(为了便于阅读,将大流分离到小私有方法中)