ref关键字在C#中返回类型之前的含义是什么

在下面的代码中, GetAge()方法签名中ref的意义是什么?

 public class Person { private int age; public ref int GetAge() { return ref this.age; } } 

ref return是C#7.0中的一个新function。 它允许返回对内存位置的引用。 这在以前的C#版本中是不可能的。 您甚至可以存储返回的内存位置,如下所示:

 var person = new Person(); // Here we can store the reference to the memory area and we can modify it ref int age = ref person.GetAge(); // like this age = 50; 

我们一直在同一个内存位置工作,而不是age副本


幕后发生了什么?

如果我们有这个代码:

 public class Program { public static void Main() { var person = new Person(); // Here we can store the reference to the memory area and we can modify it ref int age = ref person.GetAge(); // like this age = 50; } } public class Person { private int age; public ref int GetAge() { return ref this.age; } } 

以下是编译器(Roslyn)为该代码幕后操作的内容:

 using System; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Security; using System.Security.Permissions; [assembly: AssemblyVersion("0.0.0.0")] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [module: UnverifiableCode] public class Program { public unsafe static void Main() { Person person = new Person(); int* age = person.GetAge(); *age = 50; } } public class Person { private int age; public unsafe int* GetAge() { return ref this.age; } } 

好!!! 我想我们都很高兴我们不必处理所有这些恶作剧。


这个function什么时候有用?

通过避免复制值或多次执行解除引用操作,添加ref本地和ref返回使算法更有效。

当您处理值为数据类型( struct )的大型数据结构并将副本传入和传出方法可能不是非常有效时,它最有用。 例如,假设我们有一个包含一堆struct对象的类:

 class Container { private Tile[] tiles = new Tile[] { new Tile { X = 10 } }; public Tile this[int x] { get { return tiles[x]; } set { tiles[x] = value; } } } public struct Tile { public int X { get; set; } // Many more propeties } 

如果我们想使用Tile对象,因为它们是struct ,我们将无法执行此操作:

 var container = new Container(); container[0].X = 10; 

我们不能这样做,因为编译器会发出以下错误:

错误CS1612无法修改’Container.this [int]’的返回值,因为它不是变量

编译器抛出该错误以明确表明您认为自己在做什么(修改索引项),并不是您正在做的事情。 您实际上正在修改副本,因此它会强制您执行此操作。 因此,为了能够设置X,您需要在副本上执行此操作:

 var container = new Container(); var copy = container[0]; copy.X = 10; // now we need to set the item to the copy container[0] = copy; 

正如您所看到的那样效率不高,尤其是当我们使用大型struct ,我们需要以迭代方式操作其中的许多struct

使用C#7.0,我们可以这样做:

 public ref Tile this[int x] { get { return ref tiles[x]; } } 

现在我们可以直接操作Tile ,而无需发送副本,制作副本,然后将原始项目设置为副本。 像这样:

 var container = new Container(); ref Tile tile = ref container[0]; tile.X = 10; 

一个小问题

网上有很多例子,它们的语法如下:

 // Notice the ref missing on the right side ref int age = person.GetAge(); 

这将导致此错误:

无法使用值初始化by-reference变量

正确的语法是让双方的ref像这样:

 ref int age = ref person.GetAge(); 

更多信息

这是一个SO问题,其中已经讨论了这个特征。 我想这个问题现在已成为历史 。 以下是Eric Lippert关于此function的另一篇文章。