CodeGym /课程 /C# SELF /函数返回多个值:out参数和元组

函数返回多个值:out参数和元组

C# SELF
第 11 级 , 课程 3
可用

1. 入门

想象一下,我们有个函数,传入一个用户(比如名字),要一次性返回年龄、注册日期和活跃标志。在C和早期C#版本里,函数只能返回一个值是很正常的。如果要返回多个值怎么办?这个问题催生了各种方案,每种都有自己的优缺点。
在前面的课里我们已经见过元组了。现在来学学out参数,并且对比这两种方式。

最常用的几种方式:

  • out参数。
  • 返回一个带所需字段的对象(匿名类型或自定义类)。
  • 返回元组(ValueTuple)。

这节课我们会详细看两种方式——out参数和元组,来个“正面对决”,看看各自的优点,帮你选最适合自己函数多返回值的办法。

2. out参数:来自过去的问候

看到这种函数的时候:


void GetUserInfo(string userName, out int age, out DateTime registrationDate, out bool isActive)
{
    // 这里做计算
    age = 42;
    registrationDate = new DateTime(2010, 1, 1);
    isActive = true;
}

你可能会想:这是函数还是个小型洗车店?一下子返回这么多东西,而且都不是主返回值!

怎么用

调用方要提前声明好变量,函数会把它们填上:

int age;
DateTime reg;
bool isActive;

GetUserInfo("Bob", out age, out reg, out isActive);

// 现在所有变量都被赋值了
Console.WriteLine($"{age}, {reg}, {isActive}");

out方式的缺点

  • 阅读更难:方法签名变得很长,参数名不一定能直接看懂返回的是什么。
  • 链式调用不方便:这种方法不能直接放到链式调用里(比如直接把结果传给另一个方法)。
  • 会修改传入变量:方法必须修改已有变量;如果忘了加out,编译器会报错。
  • 初始化有点麻烦:编译器要求你先声明外部变量,即使你只用一次结果。
  • 大方法里可读性差:如果out参数太多,很容易搞混顺序和用途。

这时候元组就开始发光发亮了。

3. 元组——进化版方案

举个例子对比下

用元组:


public (int Age, DateTime RegistrationDate, bool IsActive) GetUserInfo(string userName)
{
    // 模拟数据库查找
    return (42, new DateTime(2010, 1, 1), true);
}

怎么用:

// 一次性拿到所有值,还能给变量起名字
var (age, regDate, isActive) = GetUserInfo("Bob");
Console.WriteLine($"{age}, {regDate}, {isActive}");

不用多声明变量,不用out,代码超清晰!

对比表:out vs tuple

对比项 Out参数 元组(ValueTuple)
签名 很长,out参数都在参数列表里 很简洁,所有值打包成一个“快递”
用法 要先声明变量,再调用方法 可以直接解构赋值
可读性 out参数多时经常看不清 元素名字一目了然
方便组合吗? 不方便 可以嵌套、传递都很灵活

元组 VS. out——底层发生了啥

out参数时,函数其实是在操作自己“地盘”外的内存:简单说,就是它会改掉别处声明的变量。这需要小心,不然很容易把变量搞乱(还好编译器强制你必须赋值!)。

元组其实就是个数据结构,函数创建好、初始化好,然后整体返回。这样所有东西都打包好,不会丢,也不会忘。

代码阅读和维护

你肯定同意——过一周再看别人的代码,肯定更想看到:

(var age, var city, var isActive) = GetUserInfo("Anna");

而不是

int age;
string city;
bool isActive;
GetUserInfo("Anna", out age, out city, out isActive);

元组让方法签名更简洁,结果用起来也更直观。

4. 哪些场景元组特别好用

1. 需要返回结果和错误信息时

public (bool Success, string ErrorMessage) TryProcess(string data)
{
    if (string.IsNullOrEmpty(data))
        return (false, "没有数据");

    // 处理数据...
    return (true, "");
}

var (ok, error) = TryProcess(input);
if (!ok)
    Console.WriteLine($"错误: {error}");

2. 用于返回多个查找结果的函数

public (User? FoundUser, int Index) FindUserByName(User[] users, string name)
{
    for (int i = 0; i < users.Length; i++)
    {
        if (users[i].Name == name)
            return (users[i], i);
    }
    return (null, -1);
}

3. 用于“成对”值:比如求最小值和最大值

public (int min, int max) FindMinMax(int[] numbers)
{
    int min = numbers[0], max = numbers[0];
    foreach (var n in numbers)
    {
        if (n < min) min = n;
        if (n > max) max = n;
    }
    return (min, max);
}

var (minValue, maxValue) = FindMinMax(arr);
评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION