September 22, 2021

C#的值传递和引用传递

在 C# 中,形参到底是值传递还是引用传递?

在 Eentity Framework 中,会遇到一个场景:使用 DbContex 的 Savechanges 方法后,entity 的 id 就有了值。示例代码如下:

var entity = new Entity();
DbContext.Add(entity);
DbContext.SaveChanges();
// 如果 id 设置为自增主键,entity.Id 就会有由数据库返回的值

我们需要了解相关的机制,减少代码不确定性,提高稳定性。要探究这个问题,我们先来例子:

static void Main(string[] args)
{
  var custom = new CustomClass();
  SetValue(custom);
  Console.WriteLine(custom.Num);
}

public static void SetValue(CustomClass innerCustom)
{
  innerCustom = new CustomClass();
  innerCustom.Num = 1;
}

public class CustomClass
{
  public int Num { get; set; }
}

在上面例子中,custom 是引用类型,所以 custom 本身只是一个引用地址。

此时在 SetValue 方法中,将 innerCustom 重新赋值新的 CustomClass 对象,innerCustom 必定为新对象的引用地址。如果给 innerCustom 赋值新对象后, custom 也变了,说明 custome 与 innerCustom 是同一个值。如果 custome 没有变,说明 custome 与 innerCustom 只是指向同一个引用地址。

但实际打印出的结果是 custom.Num 为 0,SetValue 方法内的赋值对 custom 并不生效,说明方法中的形参 innerCustom 是 custom 的副本。

并且 .NET 提供了 ref 关键字,用于将形参变为引用传递。

回到最初的话题,如果 innerCustom 没有被赋值新对象,那么 innerCustom 肯定是与 custom 指向同一个引用对象。在这个情况下对 innerCustom 属性的赋值,必定会反应到 custom。那么在 SaveChanges 方法内对 entity 的属性 id 赋值,即可在外部获取到 id 值。

参考资料:传递值类型参数 - C# 编程指南 | Microsoft Docs