繁体   English   中英

直接使用返回值与局部变量有何不同

[英]How is direct use of return value different from local variable

Memory<T>被介绍为“ Span<T>的包装器,因此您可以在异步/迭代器方法中使用Span ”。 我理解为什么不能在异步中使用Span ,但是ref struct类型让我认为我从来没有正确理解参数和返回值的概念。 说“使用Memory.Span创建Span作为异步方法中的参数,因为您不能在异步方法中使用Span ”对我来说听起来有悖常理。 代码中解释:

async Task<ReadOnlyMemory<char>> GetMemory(string text) => text.AsMemory();
async Task foo(string text)
{
    var memory = await GetMemory(text);

    // this is valid code
    ConsumeSpan(memory.Span);

    // this is invalid code
    var textSpan = memory.Span;
    ConsumeSpan(textSpan);
}

有效代码的行为与无效代码相同。 想知道Memory.Span可以在 CLR 中实现一些特殊的行为,我试过这个:

Span<char> CreateSpan() => new Span<char>();
async Task bar(string text) {
    // both statements are valid
    CreateSpan();
    _ = CreateSpan();
}

这证伪了我的猜想,让我意识到我可能对生活在方法中的价值观有一个错误的心理模型。 C# 语言中关于有名字和没有名字的值有什么不同吗? 可能回答我自己的问题,带名称的值是变量的定义,因此变量和“未命名值”之间必须存在一些差异。 当我直接将 Span 用作函数参数时,是否会在我的 foo 方法的堆栈上创建 Span 的本地副本,或者这是语言未指定的内容并将其留给优化器决定? 您对日常编程中的未命名值有不同的看法吗? 查看 ref 返回也让我打破了我对未命名变量的假设:

int x = 0;
ref int GetRef() => ref x;
void foobar()
{
    GetRef() = 42;
}

您所说的“命名变量”与其他变量之间存在一个主要区别。 在发布模式下,两者的行为相同。 但是在调试模式下,命名变量的生命周期会延长到作用域结束,以便调试器可以随时检查它们。

基本上,请考虑以下代码:

async Task bar(string text) 
{
    var a = GetValue();
    await Task.Yield();
}

如果你把一个断点右括号} ,如果在调试模式下运行时,您将能够检查的值a 在发布模式下,该值将被优化掉。

这就是为什么在异步方法中编写var a = CreateSpan()是非法的。 在发布模式下的某些条件下它可能是安全的,但它会导致变量的范围在调试模式下以不安全的方式扩展。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM