• C#常见面试题:ref、out 和 in有什么区别
  • 发布于 20小时前
  • 38 热度
    0 评论
在 C# 里,方法传参默认是按值传递的。也就是说,你传进去的是变量的一个“复印件”,方法里怎么折腾这个副本,都不会影响外面的原始变量。但有时候我们就是想让方法直接“动真格”——操作原始变量本身。这时候就得请出三位“重量级选手”:ref、out 和 in。它们的作用是:按引用传递,让方法和调用方操作的是同一块内存。但三个人性格不同,用法也大不一样。

1. ref 参数——能读能改,真正的“双向奔赴”
ref 是“reference”(引用)的缩写,它能让方法直接读取并修改原始变量。
⚠️ 注意:变量必须先初始化才能传给 ref,不然编译器不答应。
现实场景:比如银行系统里算利息,方法直接把账户余额拿过来改了,改完外面立刻生效。
using System;
publicclassBank
{
    public void ApplyInterest(ref decimal balance, decimal interestRate)
    {
        balance += balance * interestRate / 100;
        Console.WriteLine($"Balance after applying interest: {balance}");
    }
}
publicclassProgram
{
    public static void Main()
    {
        decimal accountBalance = 1000m;
        Bank bank = new Bank();
        // 堆代码 duidaima.com
        Console.WriteLine($"Initial Balance: {accountBalance}");
        bank.ApplyInterest(ref accountBalance, 5);
        Console.WriteLine($"Final Balance: {accountBalance}");
    }
}
优点:
方法可以直接改值,不用靠返回值来回传,代码更简洁。
缺点:
.太“自由”了,谁都能改,容易带来意外副作用。

.必须提前初始化,不够灵活。


2. out 参数——专为“输出”而生
out 的意思是“输出”,它表示这个参数是用来从方法里“带出”值的。
最大的特点:传参前不需要初始化,但方法内部必须给它赋值,否则编译报错。
常见用法:一个方法想返回多个结果。比如登录,既要告诉你成没成功,还想告诉你是什么角色。
using System;
publicclassAuthService
{
    public bool Login(string username, string password, out string role)
    {
        if (username == "admin" && password == "1234")
        {
            role = "Administrator";
            returntrue;
        }
        elseif (username == "john" && password == "pass")
        {
            role = "User";
            returntrue;
        }
        else
        {
            role = "Guest";
            returnfalse;
        }
    }
}
publicclassProgram
{
    public static void Main()
    {
        AuthService auth = new AuthService();

        if (auth.Login("admin", "1234", outstring userRole))
        {
            Console.WriteLine($"Login successful! Role: {userRole}");
        }
        else
        {
            Console.WriteLine("Login failed.");
        }
    }
}
优点
一个方法能返回多个值,特别适合“状态 + 数据”类的场景。
缺点:

方法必须保证给 out 参数赋值,逻辑复杂时容易漏掉,维护成本高。


3. in 参数——只读引用,性能利器
in 是 C# 7.2 引入的,意思是“输入”,它按引用传参,但在方法内部是只读的,不能修改。它最大的价值在于:避免大结构体复制带来的性能开销。比如你传一个包含几十个字段的 struct,按值传递会整个拷贝一遍,而 in 只传个“指针”,省时省力。
例子:计算两个坐标点之间的距离。
using System;

publicstruct Coordinates
{
    publicdouble X { get; }
    publicdouble Y { get; }

    public Coordinates(double x, double y)
    {
        X = x;
        Y = y;
    }
}

publicclassGeoService
{
    public double CalculateDistance(in Coordinates point1, in Coordinates point2)
    {
        double dx = point2.X - point1.X;
        double dy = point2.Y - point1.Y;
        return Math.Sqrt(dx * dx + dy * dy);
    }
}
publicclassProgram
{
    public static void Main()
    {
        Coordinates location1 = new Coordinates(0, 0);
        Coordinates location2 = new Coordinates(3, 4);

        GeoService geo = new GeoService();
        double distance = geo.CalculateDistance(in location1, in location2);

        Console.WriteLine($"Distance: {distance}");
    }
}
优点:
传大结构体不复制,性能好。
只读设计,安全,不用担心被意外修改。
缺点:

.对 int、decimal 这种小类型没啥意义,反而显得啰嗦。


ref、out、in 对比表,一目了然
关键字 是否需要提前初始化 在方法内是否可修改 方法是否必须赋值 常用场景 优点 缺点
ref ✅ 必须 ✅ 可修改 ❌ 不要求 方法需要读取并更新变量 无需返回值即可修改变量 可能导致意外修改
out ❌ 不需要 ✅ 可修改 ✅ 必须赋值 返回多个结果 支持多返回值 增加方法复杂度
in ✅ 必须 ❌ 只读 ❌ 不要求 大型结构体传参 避免复制,性能更好 对小数据类型作用不大


记忆口诀(背下来,面试不慌)
ref:读写双全,灵活但危险 → “能进能出,我全都要”
out:只出不进,专为输出 → “进来是空,出去必有”
in:只进不改,安全高效 → “进来只看,不准乱动”

总结
ref、out、in 虽然都是按引用传参,但各有各的“人设”:
ref:要读也要改,变量得先有值。
out:只负责往外带值,不用初始化,但方法必须给它赋值。
in:只读模式,适合传大结构体,性能好又安全。
用得好,代码更高效、更清晰;用不好,别人看你的代码就像在读天书。所以——能不用就别滥用,该用时也别犹豫。
用户评论