我读过 .NET 支持返回引用,但 C# 不支持。有什么特殊原因吗?为什么我不能做类似的事情:
static ref int Max(ref int x, ref int y)
{
if (x > y)
return ref x;
else
return ref y;
}
return ref x
之类的东西
C# 7
做到这一点 :)
这个问题是 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++?)
您正在谈论返回对值类型的引用的方法。我知道的 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# 语言,所以我不知道不支持它的所有原因,但我认为简短的回答可能是:没有它我们可以相处得很好。
你总是可以做类似的事情:
public delegate void MyByRefConsumer<T>(ref T val);
public void DoSomethingWithValueType(MyByRefConsumer<int> c)
{
int x = 2;
c(ref x);
//Handle potentially changed x...
}
不定期副业成功案例分享
M2
返回后保持y
活着 不是更合适吗?我希望这个功能能够像捕获本地人的 lambdas 一样工作。还是您提出的行为是因为 CLR 处理这种情况的方式?