ref关键字在C#中的返回类型之前是什么意思 [英] What does the ref keyword mean before the return type in C#

查看:98
本文介绍了ref关键字在C#中的返回类型之前是什么意思的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

In the code below, what is the significance of the ref in the GetAge() method signature?

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

推荐答案

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

The ref return is a new feature in C# 7.0. It allows to return a reference to a memory position. This was not possible in previous C# versions. You can even store the returned memory location like this:

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 副本.

The whole time we were working on the same memory location and not a copy of the 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)在后台为该代码执行的操作:

Here is what the compiler (Roslyn) does behind the scenes for that code:

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!!! I think we are all glad we do not have to deal with all those * shenanigans.

此功能何时有用?

通过添加ref局部变量和ref返回,可以避免复制值或多次执行解引用操作,从而使算法效率更高.

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 对象的类:

It is most useful when you are working with large data structures which are value types (struct) and passing the copies in and out of methods may not be very effective. For example, imagine we have a class which contains a bunch of struct objects:

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 ,我们将无法执行此操作:

If we wanted to work with the Tile objects, since they are struct, we would not be able to do this:

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

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

We cannot do that because the compiler will issue this error:

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

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

编译器将抛出该错误,以明确表明您实际上在做什么(修改索引项目)不是您实际上在做什么.您实际上是在修改副本,因此它迫使您严格执行该操作.因此,要设置X,您将需要在副本上执行以下操作:

The compiler is throwing that error to be explicitly clear that what you think you are doing (modifying the indexed item), is not really what you are doing. You are actually modifying the copy so it forces you to do exactly that. So, to be able to set the X, you will need to do it on the copy like this:

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 且需要以迭代方式操纵其中的许多代码时.

As you can see that is not very efficient, especially if we are working with a large struct and we need to manipulate many of them in an iterative way.

使用C#7.0,我们可以执行以下操作:

With C# 7.0, we can do this:

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

,现在我们可以直接操作 Tile ,而不必发送副本,进行复制,然后将原始项目设置为副本.像这样:

and now we can manipulate the Tiles directly without having to send the copy, making the copy, and then setting the original item to the copy. Like this:

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


小陷阱

在线上有很多示例,它们的语法如下:

There are many examples online and they have the syntax like this:

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

这将导致此错误:

无法使用值初始化按引用变量

Cannot initialize a by-reference variable with a value

正确的语法是像这样在两侧都带有 ref :

The correct syntax is to have the ref on both sides like this:

ref int age = ref person.GetAge();


更多信息

此处是一个问题其中已讨论了此功能.我想这个问题现在是 history .并且此处是埃里克·利珀特(Eric Lippert)的另一篇有关此功能的文章.

Here is an SO question wherein this feature has been discussed. I guess that question is now history. And here is another article by Eric Lippert about this feature.

这篇关于ref关键字在C#中的返回类型之前是什么意思的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆