【问题标题】:Ref return doesn't work when struct is created in the method [duplicate]在方法中创建结构时,参考返回不起作用[重复]
【发布时间】:2020-07-25 07:48:08
【问题描述】:

为什么这不起作用?
我创建了结构并希望通过 ref 将其返回。

public readonly struct AuditResult
{
    public readonly bool AcceptChanges;
    public readonly string Reason;

    public AuditResult(bool acceptChanges, string reason)
    {
        AcceptChanges = acceptChanges;
        Reason = reason;
    }

    public static ref AuditResult AcceptAuditResult()
    {
        var auditResult = (new AuditResult(true, string.Empty));
        ref AuditResult res = ref auditResult;

        return ref res;
    }
}

发生此错误:

CS8157 无法通过引用返回“res”,因为它已初始化为无法通过引用返回的值

在这种情况下我的变量是ref

【问题讨论】:

  • Ref 结构体存在于堆栈中。当一个方法返回时,它的堆栈帧被释放,包括它分配的任何 ref 结构,因此对该内存的任何引用都是无效的,编译器知道这是不安全的。

标签: c# ref c#-7.0


【解决方案1】:

这是 C++ 或 Rust 等非托管语言中的常见错误 - 通过使用 ref 语义,您在决定管理自己的内存时有效地编写代码。

考虑以下一点 C++:

char* Greet(char* name)
{
  char buffer[100];
  sprintf(buffer, "Hello, %s!", name);
  return buffer;
}

一旦方法退出,buffer 就会超出范围 - 它不再存在,您将留下一个悬空指针。这种模式称为RAII - Resource acquisition is initialization

您正在尝试在这里做类似的事情 -

ref var something = ...
return ref res;

该局部变量超出范围 - 您将尝试返回对不存在的东西的引用。

但是为什么ref return首先存在呢?

按引用返回意味着只复制引用,而不复制结构。 有时,创建一个新结构可能会很昂贵。

static readonly AuditResult AcceptWithNoReason = 
    new AuditResult(true, string.Empty);

public static ref readonly AuditResult AcceptAuditResult()
{
    return ref AcceptWithNoReason; //this is valid
}

但是你必须返回一个比该方法调用具有更长生命周期的东西的引用。阅读更多here

【讨论】:

    【解决方案2】:

    C# documentation 声明:

    返回值的生命周期必须超出方法的执行范围。换句话说,它不能是返回它的方法中的局部变量。它可以是类的实例或静态字段,也可以是传递给方法的参数。尝试返回局部变量会生成编译器错误 CS8168,“无法通过引用返回本地 'obj',因为它不是本地引用。”

    为了使用 return ref 关键字,您需要返回一个不是局部变量的对象,因为局部变量将超出范围并被垃圾回收。相反,请考虑返回对类/结构中成员变量的引用,而不是 res。此外,请考虑是否需要通过引用返回值 - 如果您没有在内部其他地方访问它,则无需通过引用传递它。


    但是请注意,您可以在本地使用 ref 关键字为局部变量名称创建别名,如下所示:

    Foo a = new Foo();
    ref Foo b = ref a;
    

    这里,修改b也会修改a。但是,使用这种语法,您不能将本地引用传递到当前方法范围之外。

    【讨论】:

      猜你喜欢
      • 2016-10-13
      • 2015-08-30
      • 2015-07-14
      • 2017-12-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多