我们何时应该在C#中使用out
参数?
例如
bool TryGetValue(out object value);
VS
class ReturnType
{
public bool Found {get;set;}
public object Value {get;set;}
}
ReturnType TryGetValue();
除了减少代码行数外,何时应使用out
参数以及何时应将其作为返回类型返回?
答案 0 :(得分:4)
Out也可用于可能失败的操作(通常在启动Try *的方法中找到)。
E.g。 TryParse将返回一个bool,指示成功/失败,同时使用out值作为结果。这样可以避免抛出异常。
答案 1 :(得分:3)
你已经确切地说明了应该使用它的原因。为了降低代码复杂性。
if (TryGetValue(myObj))
{
[...]
}
比
更整洁Result tryGetValueResult = TryGetValue();
if (tryGetValueResult.Found)
{
[...]
}
当结果需要作为引用类型时,它也可以节省垃圾。
答案 2 :(得分:3)
如果没有一般理由将多个值封装在一起,除了这个调用之外,那么创建一个单独的类型可能就在顶层。
另一方面,如果您有多个输出参数和一个逻辑上属于一起的返回值(例如,名字,姓氏,电话号码),那么创建一个合适的类型(例如“联系人”)可能是有意义的并返回。
TryGetValue
选项的一个替代方法是使用可空值类型,如果有问题的值是值类型。例如,int.TryParse可能有一个签名:
int? TryParse(string text)
(当然过载占用IFormatProvider
)。
答案 3 :(得分:3)
它们在从构造函数返回值所需的(罕见)情况下非常有用。例如, Mutex 构造函数有一个布尔输出参数,该参数设置为指示是否创建了新的互斥锁,或者是否存在已存在名称的现有互斥锁。
答案 4 :(得分:2)
out关键字通过编译器执行一些操作。
调用者不必初始化参数。被调用者无法读取参数,但必须在退出方法之前写入。
更重要的是使意图可见,因为调用者在进行方法调用时必须指定out关键字
当需要从方法中返回多个值(没有从对象[]中填充和去填充它们时)时,可以使用。 (喜欢从每个函数返回bSuccess的部分都会喜欢out关键字。)
在您发布的示例中.. TryParse的主要返回值是解析操作的成功。这就是它的返回值 - 但最可能的后续需求是获取解析后的对象(如果成功)。因此,TryParse不是让所有调用者都执行该步骤,而是通过将其作为out param来为您节省麻烦..因为它已经将其作为CanParse检查的一部分。
答案 5 :(得分:1)
输出参数通常是脆弱的一面。超越示例,一般地看待问题:Bill Wagner的书“更有效的C#”描述了一个非常聪明的方法,它也有详细描述here。
以下代码适用于此实例。
public class Tuple<T1,T2>
{
public T1 First {get;private set;}
public T2 Second {get; private set;}
Tuple(T1 first, T2 second)
{
First = first;
Second = second;
}
}
using ComplexPair = Tuple<bool,object>;
public class SomeOtherClass
{
public ComplexPair GetComplexType ()
{
...
return new ComplexPair(true, new object);
}
}
答案 6 :(得分:1)
最好使用类似Option类型的东西作为可能不存在的返回类型的容器。这些在大多数函数语言中都很流行,比如Scala。适用于您只关心某些事情是成功还是失败的情况,而您并不关心原因。例如解析整数。
int num; // mutable = bugprone
if (!int.TryParse(str, out num)) // branching = complexity
num = someDefault;
使用Option类型,您可以定义一个包含可变丑陋的int解析器并返回一个干净的Option。如果只在一个地方,这可以降低您的复杂性。避免重复和变异。
public Option<int> IntParse(string str) {
int num; // mutable
if (!int.TryParse(str, out num))
return Option.None<int>();
else
return Option.Some<int>(num);
}
在其他地方使用:
int result = IntParse(someString).GetOrElse(defaultValue);
正如您所看到的,由于分支已隐藏,因此导致使用模式明显减少。
或者,如果你的函数必须返回两件事,那么有可能:
想想的东西!
答案 7 :(得分:0)
如果object可以为null。 不需要实例化。
答案 8 :(得分:0)
我会投票使用返回类型。尽管C#不是一种函数式语言,但我认为瞄准函数式编程风格是件好事。不是为了学术上的纯洁,而是为了实用的好处,每个功能的行为都是非神秘的,没有副作用。
答案 9 :(得分:0)
如果您希望函数只返回对现有对象的引用或创建新对象,则只应使用out参数。
答案 10 :(得分:0)
在我的公开场合都是正确的,但我发现返回一个更优雅的复杂类型,特别是如果它是泛型类型
ReturnType<T>
这提供了有关该值将会是什么的更多信息,因此您不会猜测Value原始类型并进行转换。
答案 11 :(得分:-3)
我想保留成功指标的返回值。要么是成功的简单的真/假,要么是更复杂的东西,比如0表示成功,还有其他值表示错误是什么。
这意味着程序员可以测试您编写的每个函数是否成功。 (当然,并非所有人都愿意,但可以)
然后需要 out 参数来从函数中检索值。