在下面的代码中,方法签名中的ref
有什么意义?ref关键字在C#中的返回类型之前意味着什么
public class Person
{
private int age;
public ref int GetAge()
{
return ref this.age;
}
}
在下面的代码中,方法签名中的ref
有什么意义?ref关键字在C#中的返回类型之前意味着什么
public class Person
{
private int age;
public ref int GetAge()
{
return ref this.age;
}
}
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关于此功能的另一篇文章。
使不变性哭泣的特征:),与元组相同使得可读性哭泣:) – Fabio
@fabio你是诗人吗? ;) – CodingYoshi
我想如果这是在一个工作日中间发布的话,你会得到更多的问题和回答upvotes :) –
@GiladGreen我在工作时很忙,有时我忘了吃东西;) – CodingYoshi