题
如果我们想从方法中获取值,我们可以使用任一返回值,如下所示:
public int GetValue();
或者:
public void GetValue(out int x);
我不太明白它们之间的区别,所以不知道哪个更好。你能给我解释一下吗?
谢谢。
解决方案
返回值都差不多 总是 当该方法没有其他内容可返回时,这是正确的选择。(事实上,我想不出任何情况下我会 曾经 想要一个 void 方法 out
参数,如果我有选择的话。C# 7 的 Deconstruct
语言支持的解构方法是这条规则的一个非常非常罕见的例外。)
除此之外,它还使调用者不必单独声明变量:
int foo;
GetValue(out foo);
与
int foo = GetValue();
Out 值还可以防止像这样的方法链接:
Console.WriteLine(GetValue().ToString("g"));
(事实上,这也是属性设置器的问题之一,这就是构建器模式使用返回构建器的方法的原因,例如 myStringBuilder.Append(xxx).Append(yyy)
.)
此外,输出参数与反射一起使用会稍微困难一些,并且通常也会使测试变得更加困难。(通常会投入更多精力来简化模拟返回值而不是输出参数)。基本上我想不出他们做了什么 更轻松...
返回值 FTW。
编辑:就正在发生的事情而言...
基本上,当您传入“out”参数的参数时,您 有 传递一个变量。(数组元素也被归类为变量。)您调用的方法在其堆栈上没有用于参数的“新”变量 - 它使用您的变量进行存储。变量中的任何更改都会立即可见。下面是一个显示差异的示例:
using System;
class Test
{
static int value;
static void ShowValue(string description)
{
Console.WriteLine(description + value);
}
static void Main()
{
Console.WriteLine("Return value test...");
value = 5;
value = ReturnValue();
ShowValue("Value after ReturnValue(): ");
value = 5;
Console.WriteLine("Out parameter test...");
OutParameter(out value);
ShowValue("Value after OutParameter(): ");
}
static int ReturnValue()
{
ShowValue("ReturnValue (pre): ");
int tmp = 10;
ShowValue("ReturnValue (post): ");
return tmp;
}
static void OutParameter(out int tmp)
{
ShowValue("OutParameter (pre): ");
tmp = 10;
ShowValue("OutParameter (post): ");
}
}
结果:
Return value test...
ReturnValue (pre): 5
ReturnValue (post): 5
Value after ReturnValue(): 10
Out parameter test...
OutParameter (pre): 5
OutParameter (post): 10
Value after OutParameter(): 10
区别在于“后”步骤 - 即局部变量或参数更改后。在 ReturnValue 测试中,这对静态没有影响 value
多变的。在 OutParameter 测试中, value
变量由行更改 tmp = 10;
其他提示
什么更好,取决于您的具体情况。 存在 out
的一个原因是为了便于从一个方法调用中返回多个值:
public int ReturnMultiple(int input, out int output1, out int output2)
{
output1 = input + 1;
output2 = input + 2;
return input;
}
因此,一个人的定义并不比另一个好。但通常你会想要使用一个简单的回报,除非你有上述情况。例如。
修改强> 这是一个示例,说明关键字存在的原因之一。上述内容绝不是最佳实践。
您通常应该选择返回值而不是out param。如果你发现你自己编写需要做两件事的代码,那么params就是一种诡计。一个很好的例子是Try模式(例如Int32.TryParse)。
让我们考虑两种方法的调用者必须做什么。对于第一个例子,我可以写这个......
int foo = GetValue();
请注意,我可以声明一个变量并通过您的方法在一行中分配它。对于第二个例子,它看起来像这样......
int foo;
GetValue(out foo);
我现在被迫先声明我的变量并将我的代码写成两行。
<强>更新强>
在询问这些类型的问题时,一个好看的地方是.NET Framework设计指南。如果您有图书版本,那么您可以看到Anders Hejlsberg和其他人关于此主题的注释(第184-185页),但在线版本在这里...
http://msdn.microsoft.com/en -us /库/ ms182131(VS.80)的.aspx
如果你发现自己需要从API返回两个东西,那么将它们包装在struct / class中会比out param更好。
有一个理由使用 out
尚未提及的参数:调用方法必须接收它。如果您的方法产生调用者不应丢弃的值,请将其设为 out
强制调用者明确接受它:
Method1(); // Return values can be discard quite easily, even accidentally
int resultCode;
Method2(out resultCode); // Out params are a little harder to ignore
当然调用者仍然可以忽略 价值 在一个 out
param,但你已经提请他们注意了。
这是一种罕见的需求;更常见的是,您应该对真正的问题使用异常,或者返回一个带有状态信息的对象以供“仅供参考”,但在某些情况下这可能很重要。
主要是偏好
我更喜欢退货,如果您有多个退货,您可以将它们包装在结果DTO中
public class Result{
public Person Person {get;set;}
public int Sum {get;set;}
}
您几乎应该总是使用返回值。 ' out
'参数会对许多API,组合等产生一些摩擦。
最值得注意的异常是想要返回多个值(.Net Framework在4.0之前没有元组),例如使用 TryParse
模式。
您只能有一个返回值,而您可以有多个输出参数。
在这些情况下,您只需要考虑参数。
但是,如果您需要从方法中返回多个参数,您可能希望查看从OO方法返回的内容,并考虑是否最好使用这些参数返回对象或结构。因此,您将再次返回返回值。
我希望以下代替这个简单示例中的任何一个。
public int Value
{
get;
private set;
}
但是,它们都非常相似。通常,如果需要从方法中传回多个值,则只能使用“out”。如果要在方法中输入和输出值,可以选择“ref”。我的方法是最好的,如果你只返回一个值,但如果你想传递一个参数并获得一个值,那么你可能会选择你的第一选择。
它们都有不同的用途,编译器不会对它们进行相同的处理。如果您的方法需要返回一个值,那么您必须使用return。 Out用于您的方法需要返回多个值的位置。
如果使用return,则首先将数据写入方法堆栈,然后再写入调用方法。在out的情况下,它直接写入调用方法堆栈。不确定是否还有其他差异。
没有真正的区别,out参数在C#中允许方法返回多于一个值,即全部。
然而,有一些细微的差别,但不是它们真的很重要:
使用out参数将强制您使用两行,如:
int n;
GetValue(n);
使用返回值时,您可以在一行中执行此操作:
int n = GetValue();
另一个区别(仅对值类型正确并且仅当C#没有内联函数时)是使用返回值必然会在函数返回时使用OUT参数复制该值而不一定这样做。
正如其他人所说的那样:回报价值,而不是出现参数。
我可以向您推荐“框架设计指南”一书吗? (第2版)?第184-185页介绍了避免使用params的原因。整本书将引导您在各种.NET编码问题上朝着正确的方向前进。
与框架设计指南结盟是使用静态分析工具FxCop。您可以在Microsoft的网站上找到这个免费下载。在编译的代码上运行它,看看它说的是什么。如果它抱怨成百上千的事情......不要惊慌!平静而细致地看待每个案例的内容。不要急于尽快解决问题。了解它告诉你的是什么。你将被置于掌握的道路上。
我认为有用的几个场景之一就是在使用非托管内存时,你想要明确表示“返回”内存。价值应该手工处理,而不是期望它自己处理。
此外,返回值与异步设计范例兼容。
您无法指定功能“async”如果它使用ref或out参数。
总之,返回值允许方法链接,更清晰的语法(通过消除调用者声明其他变量的必要性),并允许异步设计,而不需要在将来进行实质性修改。
使用返回类型为bool的out关键字有时可以减少代码膨胀并提高可读性。 (主要是当out参数中的额外信息经常被忽略时。)例如:
var result = DoThing();
if (result.Success)
{
result = DoOtherThing()
if (result.Success)
{
result = DoFinalThing()
if (result.Success)
{
success = true;
}
}
}
VS
var result;
if (DoThing(out result))
{
if (DoOtherThing(out result))
{
if (DoFinalThing(out result))
{
success = true;
}
}
}
out会更有用。
实施例
public BookList Find(string key)
{
BookList book; //BookList is a model class
_books.TryGetValue(key, out book) //_books is a concurrent dictionary
//TryGetValue gets an item with matching key and returns it into book.
return book;
}
返回值是您的方法返回的正常值。
如果 out 参数,well out和ref是C#的2个关键词,它们允许将变量作为引用传递。
ref 和 out 之间的最大区别是, ref 应该在之前初始化, out 不要
我怀疑我不会对这个问题有所了解,但我是非常经验丰富的程序员,我希望一些更开明的读者会关注。
我认为它更适合面向对象的编程语言,因为它们的价值回归程序(VRP)具有确定性和纯粹性。
'VRP'是一个函数的现代学术名称,它被称为表达式的一部分,并且具有一个返回值,在表达式的评估过程中,它会在理论上替换该调用。例如。在诸如 x = 1 + f(y)
之类的语句中,函数 f
充当VRP。
'确定性'意味着函数的结果仅取决于其参数的值。如果使用相同的参数值再次调用它,则肯定会得到相同的结果。
'Pure'意味着没有副作用:调用函数除计算结果外什么都不做。在实践中,这可以解释为没有重要的副作用,因此如果VRP每次调用时都会输出调试消息,例如,可能会被忽略。
因此,如果在C#中,你的函数不是确定性的和纯粹的,我说你应该把它变成 void
函数(换句话说,不是VRP),以及它需要的任何值return应该在 out
或 ref
参数中返回。
例如,如果你有一个从数据库表中删除某些行的函数,并且你希望它返回它删除的行数,你应该声明它是这样的:
public void DeleteBasketItems(BasketItemCategory category,out int count);
代码>
如果您有时想要调用此函数但未获得 count
,则可以始终声明重载。
您可能想知道为什么这种风格更适合面向对象的编程。从广义上讲,它适合于一种可能(有点不精确地)称为“过程式编程”的编程风格,它是一种过程编程风格,可以更好地适应面向对象的编程。
为什么呢?对象的经典模型是它们具有属性(也称为属性),并且您通过读取和更新这些属性来查询和操纵对象(主要是)。过程编程风格往往使得执行此操作变得更容易,因为您可以在获取和设置属性的操作之间执行任意代码。
程序编程的缺点是,因为你可以在任何地方执行任意代码,你可以通过全局变量和副作用获得一些非常钝的和容易受到漏洞影响的交互。
因此,非常简单,向读取代码的人发出信号是一种好习惯,即函数可以通过使其返回非值来产生副作用。