C#7.2引入了in修饰符,用于通过引用传递参数,并保证接收者不会修改参数.
这篇文章说:
你永远不应该使用非readonly结构作为in参数,因为它可能会对性能产生负面影响,如果结构是可变的,可能会导致模糊的行为
这是什么意思为内置原语,例如int,double?
我想in用来表达代码中的意图,但不是以防御性副本的性能损失为代价.
问题
in参数传递原始类型并且没有制作防御性副本是否安全?DateTime,TimeSpan,Guid,...考虑readonly由JIT?
C# 7.2 添加了两个新特性:
输入参数
使用in的参数让我们通过引用传递,但随后阻止我们将值分配给它。然而,性能实际上会变得更糟,因为它创建了结构的“防御性副本”,复制了整个内容
只读结构
解决此问题的一种方法是使用readonlyfor a struct。当您将它传递给一个in参数时,编译器会看到它readonly并且不会创建防御性副本,从而使其成为更好的性能替代方案。
这一切都很棒,但该领域的每个领域struct都必须如此readonly。这不起作用:
public readonly struct Coord
{
public int X, Y; // Error: instance fields of readonly structs must be read only
}
Run Code Online (Sandbox Code Playgroud)
自动属性也必须是readonly。
有没有办法获得in参数的好处(编译时检查以强制参数不被更改,通过引用传递)同时仍然能够修改 的字段struct,而不会in因创建防御副本?
在 C# 7.2 中,我们看到了in方法参数修饰符的引入,以将只读引用传递给对象。我正在使用 7.2 开发一个新的 .NET Standard 项目,出于好奇,我尝试in在结构的相等运算符的参数上使用关键字进行编译。
IE - public static bool operator == (in Point l, in Point r)
不是 - public static bool operator == (Point l, Point r)
我最初对这行得通感到有点惊讶,但经过仔细思考后,我意识到这两个版本的运算符之间可能没有功能差异。我想确认这些怀疑,但经过一番彻底的搜索后,我找不到任何明确谈论in在运算符重载中使用关键字的内容。
所以我的问题是这是否真的有功能差异,如果有,是否有任何特别的理由鼓励或阻止使用inwith 运算符参数。我最初的想法是没有区别,特别是如果操作符是内联的。但是,如果确实有所作为,似乎 in 参数应该在任何地方使用(只读引用有意义的任何地方,即),因为它们提供了速度奖励,并且与refand不同out,不需要用户预先添加传递对象时的那些关键字。这将允许更有效的值类型对象传递,而无需对方法和运算符的用户进行任何更改。
总的来说,这可能超出了大多数 C# 开发人员担心的那种小规模优化,但我很好奇它是否有效果。
...特别是in(readonly ref)参数.这是我的情况:
我在同一个Visual Studio解决方案中有一个UWP项目和一个UWP单元测试项目.两个项目都以C#7.2为目标.主要的UWP项目有这个类(注意in参数):
public struct Cell
{
public Cell(int x, int y)
{
X = x;
Y = y;
}
public int X { get; }
public int Y { get; }
public static Cell operator +(in Cell left, in Cell right)
{
return new Cell(left.X + right.X, left.Y + right.Y);
}
public static Cell operator -(in Cell left, in Cell right)
{
return new Cell(left.X - right.X, left.Y - right.Y);
}
public …Run Code Online (Sandbox Code Playgroud)