张赐荣——一位视障程序员。
赐荣小站: www.prc.cx

張賜榮

张赐荣的技术博客

博客园 首页 新随笔 联系 订阅 管理

C#方法返回多个值

问题

在许多情况下,从一个方法返回一个值是不够的。您需要一种方式来从一个方法返回不止一个数据项。

解决办法

对充当返回参数的参数使用关键字 out 。下面的方法接受一个 inputShape 参数,并通过该值计算 height 、width 和 depth 。

public void ReturnDimensions(int inputShape,
out int height,
out int width,
out int depth)
{
height = 0;
width = 0;
depth = 0;
//从inputShape值计算高度,宽度,深度
}

这个方法以如下方式进行调用:
// 调用方法并返回height、width和depth的值
Obj.ReturnDimensions(1, out var height, out var width, out var depth);
另一个方法将返回一个包含所有返回值的类或结构。修改前一个方法,使其返回一个结构,而不是使用 out 参数:

public Dimensions ReturnDimensions(int inputShape)
{
// The default ctor automatically defaults this structure抯 members to 0
Dimensions objDim = new Dimensions();
// Calculate objDim.Height, objDim.Width, objDim.Depth from the inputShape value
return (objDim);
}

其中 Dimensions 的定义如下所示。

public struct Dimensions
{
public int Height;
public int Width;
public int Depth;
}

现在以如下方式调用这个方法。
// 调用方法并且返回height、width和depth Dimensions
objDim = obj.ReturnDimensions(1);
除了从此方法返回一个用户定义的类或结构,也可以用一个 Tuple 对象包含所有的返回值。修改前一个方法,使其返回一个 Tuple 。

public Tuple<int, int, int> ReturnDimensionsAsTuple(int inputShape)
{
// 根据 inputShape 值计算 objDim.Height, objDim.Width, objDim.Depth
// 例 {5, 10, 15}
//创建具有计算结果值的元组
var objDim = Tuple.Create<int, int, int>(5, 10, 15);
return (objDim);
}

现在以如下方式调用这个方法。
// 调用方法并且返回height、width和depth
Tuple<int, int, int> objDim = obj.ReturnDimensions(1);

讲解

在方法签名中使用 out 关键字创建一个参数,指示这个参数将由该方法初始化并返回。当需要方法返回多个值时,这个技巧就很有用。一个方法最多只能有一个返回值,但是通过使用 out 关键字,可以把多个参数标记为一个返回值。
要设置一个 out 参数,需要用 out 关键字标记方法签名中的参数,如下所示。
public void ReturnDimensions(int inputShape, out int height, out int width, out int depth) { ... }
要调用这个方法,还必须用 out 关键字标记调用方法的参数,如下所示。
obj.ReturnDimensions(1, out height, out width, out depth);
这个方法中的 out 参数不必初始化;只需声明它们并传入 ReturnDimensions 方法中即可。
不管在调用方法之前是否初始化过它们,在 ReturnDimensions 方法内使用它们之前都必须初始化。即使不通过 ReturnDimensions 方法内的每条路径使用它们,仍然必须初始化它们。这就是这个方法以如下三行代码开始的原因。
height = 0; width = 0; depth = 0;
您可能想知道为什么不能使用 ref 参数代替 out 参数,鉴于它们都允许一个方法改变像这样标记的参数的值。答案是,out 参数使代码有些自文档化。当遇到一个 out 参数时,您知道这个参数充当一个返回值。此外,在把 out 参数传入方法中之前,不需要做额外的工作来初始化它;而 ref 参数则需要这样做。
 在调用方法时不需要对 out 参数进行封送;相反,在方法把数据返回给调用者时对其封送一次。任何其他调用类型(按值调用或者使用 ref 关键字按引用调用)都要求在两个方向上对值进行封送。在封送场合下使用 out 关键字可以改进远程调用性能。
在仅有少量值需要返回时,out 参数是非常有用的;但是当您遇到需要返回 4 个、5 个、6 个甚至更多的值时,它就变得笨重了。另外一个返回多个值的选项是创建并返回用户定义的类或结构,或者使用 Tuple 打包需要由某个方法返回的所有值。
使用类或结构返回多个值的第一个选项非常直接。只需要像下面这样创建类型(在本例中是该类型是一个结构)即可。
public struct Dimensions { public int Height; public int Width; public int Depth; }
将需要的数据填充到这个数据结构的每个字段中,并且从方法中返回它。
与使用用户定义的对象相比,使用 Tuple 的第二个选项更加简洁。可以创建一个 Tuple ,用于包含不同类型的任意数量的值。此外,Tuple 中保存的数据是不可变的;一旦通过构造函数或者静态的 Create 方法将数据添加到 Tuple 中,就无法再修改这些数据了。
Tuple 可以接受并包含 8 个独立的值。如您需要 8 个以上的值,那么需要使用这个特别的 Tuple 类。
Tuple<T1, T2, T3, T4, T5, T6, T7, TRest> Class
当创建一个包含超过 8 个值的 Tuple 时,您无法使用静态的 Create 方法,而是必须使用 Tuple 类的构造函数。下面的代码展示了如何创建一个包含 10 个整数值的 Tuple 。
var values = new Tuple<int, int, int, int, int, int, int, Tuple<int, int, int>> ( 1, 2, 3, 4, 5, 6, 7, new Tuple<int, int, int> (8, 9, 10));
当然,您可以继续将更多的 Tuple 添加到每个内嵌的 Tuple 类的最后,以创建您需要的任何大小的 Tuple 。

参考

posted on 2022-04-07 18:09  张赐荣  阅读(602)  评论(0编辑  收藏  举报

感谢访问张赐荣的技术分享博客!
博客地址:https://cnblogs.com/netlog/
知乎主页:https://www.zhihu.com/people/tzujung-chang
个人网站:https://prc.cx/