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

Tom*_*duy 139 .net c# reference return-type

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

static ref int Max(ref int x, ref int y) 
{ 
  if (x > y) 
    return ref x; 
  else 
    return ref y; 
} 
Run Code Online (Sandbox Code Playgroud)

Eri*_*ert 187

这个问题是我的博客2011年6月23日的主题.谢谢你这个好问题!

C#团队正在考虑将其用于C#7.有关详细信息,请参阅https://github.com/dotnet/roslyn/issues/5233.

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


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

评论者"RPM1984"出于某种原因要求引用这一事实.RPM1984我建议您阅读CLI规范分区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; 
} 
Run Code Online (Sandbox Code Playgroud)

然后用它来调用它

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

我从经验上知道可以构建一个支持这些功能的C#版本,因为我已经这样做了.高级程序员,特别是移植非托管​​C++代码的人,经常会要求我们提供更多的C++ - 比如使用引用来做事情的能力,而不必在实际使用指针和固定内存的大麻烦.通过使用托管引用,您可以获得这些好处,而无需支付搞乱垃圾回收性能的成本.

我们已经考虑过这个功能,并且实际上已经实施了足够的功能,以便向其他内部团队展示他们的反馈.然而,此时根据我们的研究,我们认为该功能没有广泛的吸引力或引人注目的使用案例,使其成为真正支持的语言功能.我们还有其他更高的优先级和有限的时间和精力,因此我们不会很快就会执行此功能.

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

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;
}
Run Code Online (Sandbox Code Playgroud)

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

如果你能描述一下为什么你想要这个功能,我真的很感激.我们从真实客户那里获得的关于他们为什么需要它的信息越多,它就越有可能在某一天进入产品.这是一个可爱的小功能,如果有足够的兴趣,我希望能够以某种方式将它送到客户手中.

(另见相关的问题是否有可能返回引用在C#中的变量?而且我可以像使用C++一个C#函数内引用?)

  • @EricLippert:我没有令人信服的例子只是我想知道的事情.优秀而引人注目的回应 (4认同)
  • Eric,提供有关场景的反馈的最佳方式是什么(正如您在上一段中所建议的那样)以最大限度地提高它的可能性?MS Connect?UserVoice(具有任意10个帖子/投票限制)?别的什么? (4认同)
  • @Eric:IMHO能够让属性返回对值类型的引用是.net语言中的一个主要遗漏.如果Arr是值类型的数组(例如Point),可以说例如Arr(3).X = 9并且知道一个没有改变Arr(9).X或甚至SomeOtherArray(2)的值. X; 如果Arr是一个引用类型的数组,则不存在这样的保证.数组的索引操作符返回引用这一事实非常有用; 我认为非常不幸的是,没有其他类型的集合可以提供这样的功能. (3认同)

Ric*_*key 22

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

public struct Point
{
    public int X { get; set; }
    public int Y { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

现在创建一个该结构的数组:

var points = new Point[10];
points[0].X = 1;
points[0].Y = 2;
Run Code Online (Sandbox Code Playgroud)

在这种情况下points[0],数组索引器返回对struct的引用.编写自己的索引器(例如自定义集合)是不可能的,它具有相同的"返回引用"行为.

我没有设计C#语言所以我不知道支持它的背后的所有推理,但我认为简短的答案可能是:没有它我们可以相处得很好.

  • Tom问的是将引用*返回给变量*的方法.变量不一定是值类型,当然这通常是人们在想要ref-returns方法时所需要的.否则,分析很好; 你是对的,C#语言中唯一一个复杂表达式为用户可以操作的变量产生*ref*的地方是数组索引器.(当然,接收者和字段之间的成员访问运算符".",但这显然是对变量的访问.) (8认同)