为什么C#不支持引用的返回?
我读过.NET支持引用的返回,但C#不支持。 有特别的原因吗? 为什么我不能做这样的事情:
static ref int Max(ref int x, ref int y) { if (x > y) return ref x; else return ref y; }
这个问题是我的博客在2011年6月23日的主题 。 感谢您的好问题!
C#团队正在考虑这个C#7。详情请参阅https://github.com/dotnet/roslyn/issues/5233 。
更新:该function使它成为C#7!
你是对的; .NET不支持返回对variables的托pipe引用的方法 。 .NET还支持包含对其他variables的托pipe引用的局部variables。 (请注意,.NET不支持包含对其他variables的托pipe引用的字段或数组 ,因为这会过度复杂化垃圾回收故事。“受pipe参考variables”types也不能转换为对象 ,因此不能用作为genericstypes或方法键入参数)。
评论者“RPM1984”出于某种原因要求引用这一事实。 RPM1984我build议您阅读CLI规范Partition I第8.2.1.1节“托pipe指针和相关types”,以获取有关.NET此function的信息。
完全可以创build一个支持这两个特性的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!
我凭经验知道,可以构build支持这些function的C#版本, 因为我已经这样做了 。 高级程序员,尤其是移植非托pipeC ++代码的人,往往要求我们提供更多的C ++,就像使用引用来做事情的能力,而不必去掉实际上使用指针和固定内存的大锤。 通过使用托pipe引用,您可以获得这些优势,而无需支付浪费垃圾回收性能的成本。
我们已经考虑了这个function,并且实际上已经实施了足够的function来向其他内部团队展示他们的反馈意见。 然而,目前基于我们的研究, 我们认为该function没有足够的吸引力或令人信服的使用情况,使其成为真正的支持语言function 。 我们还有其他更高的优先级和有限的时间和精力,所以我们不会马上做这个function。
而且,正确的做法需要对CLR进行一些修改。 现在,CLR将ref-returning方法视为合法但不可validation,因为我们没有检测器来检测这种情况:
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的局部variables的内容,但该variables的生命周期已经结束! 可以写一个检测器来确定ref-returns的使用,这显然不违反堆栈安全性。 我们要做的就是编写这样一个探测器,如果探测器不能certificate堆栈的安全性,那么我们就不允许在程序那一部分使用ref返回。 这样做的开发工作量不是很大,但是testing团队要确保我们确实掌握了所有的情况,这是很大的负担。 这只是另一件事,增加了function的成本,目前的好处不超过成本。
如果你能为我描述为什么你想要这个function,我真的很感激 。 我们从真实客户得到的关于他们为什么需要的信息越多,有一天它就越有可能进入产品。 这是一个可爱的小function,如果有足够的兴趣,我希望能够以某种方式把它给客户。
(另请参见相关的问题是否有可能返回一个引用的variables在C#中吗? 我可以使用像C + +的C#函数内的引用? )
您正在讨论返回值types的引用的方法。 我知道C#中唯一的内置示例是值types的数组访问器:
public struct Point { public int X { get; set; } public int Y { get; set; } }
现在创build一个该结构的数组:
var points = new Point[10]; points[0].X = 1; points[0].Y = 2;
在这种情况下,数组索引器 points[0]
正在返回对struct的引用。 编写你自己的索引器是不可能的(例如对于一个自定义集合),它具有相同的“返回引用”行为。
我没有deviseC#语言,所以我不知道所有支持它的原因,但我认为简短的答案可能是:没有它,我们可以相处得很好。
你总是可以这样做:
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#7.0支持返回引用。 在这里看到我的答案。