cli*_*ill 17 c# out-parameters
我正在阅读核心C#编程结构,并且很难将我的头部包裹在out参数修饰符周围.我知道通过阅读它做了什么,但我想在使用它的时候想到一个场景.
有人可以给我一个真实世界的例子吗?谢谢.
Jef*_*ado 18
使用out参数的主要动机是允许函数将多个值返回给调用者,并且其他所有人都在框架中提供了示例.我将采用不同的方法来回答你的问题,首先探讨一下out参数背后的原因.我不会写出实际的例子,而是描述它们.
通常,您只有一种机制来返回值,即函数的返回值.当然你也可以使用全局(静态)或实例变量,但这一般不太实际也不安全(原因我不在这里解释). 在.NET 3.5之前,没有一种非常实用的方法可以从函数中返回多个值.如果out或ref修饰符不可用,您可以选择以下几种方法:
如果所有值都具有相同的类型,则可以返回一些值集合.在大多数情况下,这是完全正常的,您可以返回一个数字数组,字符串列表,等等.如果所有值都以完全相同的方式相关,则这是完美的.即,所有数字都是容器中的项目数,或者列表是聚会上的客人姓名.但是如果您返回的值代表不同的数量呢?如果他们有不同类型怎么办?对象列表可以包含所有对象,但这不是一种非常直观的方式来操纵那种数据.
对于需要返回多个不同类型值的情况,唯一可行的选择是创建一个新的类/结构类型来封装所有这些值并返回该类型的实例.这样做可以使用直观的名称返回强类型值,并且可以通过这种方式返回多个值.问题是,为了实现这一点,您必须使用特定名称定义类型,并且只需要能够返回多个值.如果你只想返回两个足够简单的值,那么为它创建一个类型是不切实际的呢?你还有几个选择:
您可以创建一组泛型类型,以包含固定数量的不同类型的值(如函数语言中的元组).但是,以可重复使用的方式这样做并不具有吸引力,因为它当时不是框架的一部分.它可以放在库中,但现在只是为了这些简单类型而添加了对该库的依赖.(只是很高兴.NET 4.0现在包含Tuple类型)但是这仍然无法解决这些简单值的事实,这意味着增加了简单任务的复杂性.
使用的选项是包含一个out修饰符,它允许调用者将"引用"传递给变量,以便函数可以将引用的变量设置为另一种返回值的方法.由于相同的原因,这种返回值的方式在许多方面也可以在C和C++中获得,并且在影响该决定中起到了作用.但是,C#的不同之处在于,对于out参数,函数必须将值设置为某个值.如果没有,则会导致编译器错误.这使得这不容易出错,因为通过使用out参数,您承诺调用者将值设置为某些东西并且可以使用它,编译器确保您坚持该承诺.
关于out(或ref)修饰符的典型用法的注释,很少会看到多于一个或两个out参数.在这些情况下,创建封装类型几乎总是更好的主意.如果您只需要返回一个值,通常会使用它.
但是,自从C#-3.0/.NET-3.5引入.NET 4.0中引入的匿名类型和元组以来,这些选项提供了替代方法,可以更轻松地(更直观地)返回不同类型的多个值.
Mua*_*Dib 17
有许多场景你会使用它,但主要的是你的方法需要返回多个参数的地方.举例来说,类型的TryParse方法int.在这种情况下,不是抛出异常而是将bool作为成功/失败标志返回,并且解析的int作为out参数返回.如果你打电话,int.Parse(...)你可能会抛出异常.
string str = "123456";
int val;
if ( !int.TryParse(str,out val) )
{
// do some error handling, notify user, etc.
}
Run Code Online (Sandbox Code Playgroud)
当然,看看任何TryParse方法,例如int.TryParse:
我们的想法是你真正想要2条信息:在分析操作是否成功(返回值),并且,如果是这样,什么它的结果实际上是(该out参数).
用法:
string input = Console.ReadLine();
int value;
// First we check the return value, which is a bool
// indicating success or failure.
if (int.TryParse(input, out value))
{
// On success, we also use the value that was parsed.
Console.WriteLine(
"You entered the number {0}, which is {1}.",
value,
value % 2 == 0 ? "even" : "odd"
);
}
else
{
// Generally, on failure, the value of an out parameter
// will simply be the default value for the parameter's
// type (e.g., default(int) == 0). In this scenario you
// aren't expected to use it.
Console.WriteLine(
"You entered '{0}', which is not a valid integer.",
input
);
}
Run Code Online (Sandbox Code Playgroud)
许多开发人员抱怨out参数是"代码味道"; 但在许多情况下,它们可能是迄今为止最合适的选择.一个非常重要的现代例子是多线程代码; 通常需要一个out参数来允许返回值不足的"原子"操作.
例如Monitor.TryEnter(object, ref bool),考虑获取锁并以bool原子方式设置,这是仅通过返回值无法实现的,因为锁获取必然发生在将返回值分配给bool变量之前.(是的,技术上ref和out不一样;但它们非常接近).
另一个很好的例子是System.Collections.Concurrent.NET 4.0新增的命名空间中的集合类可用的一些方法; 这些提供类似的线程安全操作,如ConcurrentQueue<T>.TryDequeue(out T)和ConcurrentDictionary<TKey, TValue>.TryRemove(TKey, out TValue).