ChatGPT解决这个技术问题 Extra ChatGPT

为什么 C# 不支持返回引用?

我读过 .NET 支持返回引用,但 C# 不支持。有什么特殊原因吗?为什么我不能做类似的事情:

static ref int Max(ref int x, ref int y) 
{ 
  if (x > y) 
    return ref x; 
  else 
    return ref y; 
} 
嗯...请引用?
C# 有值和引用类型,两者都可以返回你的意思。
我说的是return ref x之类的东西
年后,您可以使用 C# 7 做到这一点 :)

C
Community

这个问题是 my blog on June 23rd 2011 的主题。谢谢你的好问题!

C# 团队正在为 C# 7 考虑这一点。有关详细信息,请参阅 https://github.com/dotnet/roslyn/issues/5233

更新:该功能已进入 C# 7!

你是对的; .NET 确实支持返回对变量的托管引用的方法。 .NET 还支持包含对其他变量的托管引用的局部变量。 (但请注意,.NET 不支持包含对其他变量的托管引用的字段或数组,因为这会使垃圾收集故事过于复杂。此外,“对变量的托管引用”类型不能转换为对象,因此不能用作泛型类型或方法的类型参数。)

评论者“RPM1984”出于某种原因要求引用这一事实。 RPM1984 我鼓励您阅读 CLI 规范 Partition I 第 8.2.1.1 节,“托管指针和相关类型”以获取有关 .NET 的此功能的信息。

完全有可能创建一个同时支持这两个特性的 C# 版本。然后你可以做类似的事情

static ref int Max(ref int x, ref int y) 
{ 
  if (x > y) 
    return ref x; 
  else 
    return ref y; 
} 

然后用

int a = 123;
int b = 456; 
ref int c = ref Max(ref a, ref b); 
c += 100;
Console.WriteLine(b); // 556!

我凭经验知道可以构建支持这些功能的 C# 版本,因为我已经这样做了。高级程序员,尤其是移植非托管 C++ 代码的人,经常要求我们提供更多类似于 C++ 的能力来处理引用,而不必摆脱实际使用指针和到处固定内存的大锤。通过使用托管引用,您可以获得这些好处,而无需支付破坏垃圾收集性能的成本。

我们已经考虑过这个功能,并且实际上已经实现了足够多的功能,以便向其他内部团队展示以获取他们的反馈。但是,目前根据我们的研究,我们认为该功能没有足够广泛的吸引力或令人信服的使用案例,无法使其成为真正受支持的语言功能。我们还有其他更高的优先级和有限的时间和精力,所以我们不会很快推出这个功能。

此外,正确执行此操作需要对 CLR 进行一些更改。现在 CLR 将 ref-returning 方法视为合法但无法验证,因为我们没有检测器来检测这种情况:

ref int M1(ref int x)
{
    return ref x;
}

ref int M2()
{
    int y = 123;
    return ref M1(ref y); // Trouble!
}

int M3()
{
    ref int z = ref M2();
    return z;
}

M3 返回 M2 的局部变量的内容,但该变量的生命周期已经结束!可以编写一个检测器来确定明显不违反堆栈安全的 ref-return 的使用。我们要做的是编写这样一个检测器,如果检测器不能证明堆栈安全,那么我们将不允许在程序的那部分使用 ref 返回。这样做的开发工作量并不大,但要确保我们确实掌握了所有案例,这对测试团队来说是一个很大的负担。这只是将功能成本提高到现在收益不超过成本的另一件事。

如果您能向我描述为什么您需要此功能,我将不胜感激。我们从真实客户那里获得的关于他们为什么想要它的信息越多,它就越有可能在某天成为产品。这是一个可爱的小功能,如果有足够的兴趣,我希望能够以某种方式将其提供给客户。

(另请参阅相关问题 Is it Possible to Return a Reference to a Variable in C#?Can I use a reference inside a C# function like C++?


@EricLippert:我没有令人信服的例子,这只是我想知道的。出色而令人信服的回应
@Eric:在您的示例中,从 M2 返回后保持 y 活着 不是更合适吗?我希望这个功能能够像捕获本地人的 lambdas 一样工作。还是您提出的行为是因为 CLR 处理这种情况的方式?
@Eric:恕我直言,让属性返回对值类型的引用的能力是 .net 语言中的主要遗漏。如果Arr 是一个值类型(例如Point)的数组,可以说例如Arr(3).X=9 并且知道没有改变Arr(9).X 甚至SomeOtherArray(2) 的值。 X;如果 Arr 是某个引用类型的数组,则不存在此类保证。数组的索引运算符返回引用这一事实非常有用;我认为非常不幸的是,没有其他类型的集合可以提供这样的功能。
Eric,提供有关场景的反馈(如您在上一段中所建议的那样)以最大限度地提高它被看到的机会的最佳方式是什么?微软连接? UserVoice(具有任意 10 个帖子/投票限制)?还有什么?
@ThunderGr:这是“不安全”的 C# 哲学——如果您编写的代码可能是内存不安全的,那么 C# 坚持将其标记为“不安全”,以便您对内存安全负责。 C# 已经具有该功能的不安全版本,前提是所讨论的变量是非托管类型。问题是 C# 团队是否应该制作一个不安全的版本来处理托管类型。如果这样做使开发人员可以轻松编写可怕的错误,那么它就不会发生。 C# 不是 C++,它是一种可以轻松编写可怕错误的语言。 C# 在设计上是安全的。
R
Rick Sladkey

您正在谈论返回对值类型的引用的方法。我知道的 C# 中唯一的内置示例是值类型的数组访问器:

public struct Point
{
    public int X { get; set; }
    public int Y { get; set; }
}

现在创建该结构的数组:

var points = new Point[10];
points[0].X = 1;
points[0].Y = 2;

在本例中,points[0] 数组 indexer 正在返回对 struct 的引用。不可能编写具有相同“返回引用”行为的 自己的 索引器(例如用于自定义集合)。

我没有设计 C# 语言,所以我不知道不支持它的所有原因,但我认为简短的回答可能是:没有它我们可以相处得很好。


Tom 正在询问返回对变量的引用的方法。变量不必是值类型,当然这通常是人们想要返回引用的方法时想要的。否则,很好的分析;您是正确的,在 C# 语言中,复杂表达式生成对用户可以操作的变量的引用的唯一位置是数组索引器。 (当然还有接收者和字段之间的成员访问运算符“。”,但这显然是对变量的访问。)
E
Eladian

你总是可以做类似的事情:

public delegate void MyByRefConsumer<T>(ref T val);

public void DoSomethingWithValueType(MyByRefConsumer<int> c)
{
        int x = 2;
        c(ref x);
        //Handle potentially changed x...
}

C
Community

C# 7.0 支持返回引用。请参阅我的答案 here