2017-04-16 54 views
4

在下面的代码中,方法签名中的ref有什么意义?ref关键字在C#中的返回类型之前意味着什么

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

我想如果这是在一个工作日中间发布的话,你会得到更多的问题和回答upvotes :) –

+1

@GiladGreen我在工作时很忙,有时我忘了吃东西;) – CodingYoshi

回答

7

ref return是C#7.0中的新功能。它允许将参考返回到内存位置。这在以前的C#版本中是不可能的。你甚至可以存储返回的内存位置是这样的:

​​

我们正在处理相同的内存位置和整个时间不是复制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; 
    } 
} 

以下是编译器(罗斯林)确实在幕后为代码:

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; 
    } 
} 

OK!我认为我们很高兴我们不必处理所有这些诽谤。


当是这个功能有用吗?

The addition of ref locals and ref returns enable algorithms that are more efficient by avoiding copying values, or performing dereferencing operations multiple times.

当你与它是值类型(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; 

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

Error CS1612 Cannot modify the return value of 'Container.this[int]' because it is not a variable

编译器抛出这个错误是明确清楚你认为自己在做什么(修改索引项目),实际上并不是你在做什么。您实际上正在修改副本,以便强制您执行此操作。所以,为了能够设置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和我们的工作需要以迭代的方式操作其中的很多。

随着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(); 

,这将导致该错误:

Cannot initialize a by-reference variable with a value

正确的语法是具有双方的ref这样的:

ref int age = ref person.GetAge(); 

更多信息

Here是SO问题其中,该功能已被讨论。我想这个问题现在是历史here是Eric Lippert关于此功能的另一篇文章。

+1

使不变性哭泣的特征:),与元组相同使得可读性哭泣:) – Fabio

+0

@fabio你是诗人吗? ;) – CodingYoshi

相关问题