Ref 局部变量和返回结果
允许使用并返回对变量的引用的算法,这些变量在其他位置定义。 添加 ref 局部变量和 ref 返回结果可通过避免复制值或多次执行取消引用操作,允许更为高效的算法。
public static ref int Find(int[,] matrix, Func<int, bool> predicate)
{
for (int i = 0; i < matrix.GetLength(0); i++)
for (int j = 0; j < matrix.GetLength(1); j++)
if (predicate(matrix[i, j]))
return ref matrix[i, j];
throw new InvalidOperationException("Not found");
}
ref var item = ref MatrixSearch.Find(matrix, (val) => val == 42);
Console.WriteLine(item);
item = 24;
Console.WriteLine(matrix[4, 2]);
声明不可变值类型的只读结构
使用 readonly
修饰符声明 struct
将通知编译器你的意图是创建不可变类型。
readonly public struct ReadonlyPoint3D { public ReadonlyPoint3D(double x, double y, double z) { this.X = x; this.Y = y; this.Z = z; } public double X { get; } public double Y { get; } public double Z { get; } }
结构可变时声明 readonly 成员
向不改变状态的成员添加 readonly
修饰符有两个相关的好处。 首先,编译器会强制执行你的意图。 该成员无法改变结构的状态。 其次,访问 readonly
成员时,编译器不会创建 in
参数的防御性副本。
public struct Point3D { public Point3D(double x, double y, double z) { _x = x; _y = y; _z = z; } private double _x; public double X { readonly get => _x; set => _x = value; } private double _y; public double Y { readonly get => _y; set => _y = value; } private double _z; public double Z { readonly get => _z; set => _z = value; } public readonly double Distance => Math.Sqrt(X * X + Y * Y + Z * Z); public readonly override string ToString() => $"{X}, {Y}, {Z}"; }
如果使用自动实现的属性,则编译器会将 readonly
修饰符添加到 get
访问器以获取读写属性。 对于仅具有 get
访问器的属性,编译器会将 readonly
修饰符添加到自动实现的属性声明中。
请注意,readonly
修饰符对于只读属性是必需的。 编译器会假设 get
访问器可以修改状态;必须显式声明 readonly
。 自动实现的属性是一个例外;编译器会将所有自动实现的 Getter 视为 readonly
,因此,此处无需向 X
和 Y
属性添加 readonly
修饰符。
尽可能对大型结构使用 ref readonly return
语句
public struct Point3D { private static Point3D origin = new Point3D(0,0,0); public static ref readonly Point3D Origin => ref origin; // other members removed for space }
将 in
修饰符应用于大于 System.IntPtr.Size
的 readonly struct
参数
in
关键字补充了现有的 ref
和 out
关键字,以按引用传递参数。 in
关键字指定按引用传递参数,但调用的方法不修改值。
这种做法通常可以提高大于 IntPtr.Size 的只读值类型的性能。 对于简单类型(sbyte
、byte
、short
、ushort
、int
、uint
、long
、ulong
、char
、float
、double
、decimal
和 bool
以及 enum
类型),任何潜在的性能提升都是极小的。 实际上,对于小于 IntPtr.Size 的类型,使用按引用传递可能会降低性能。
避免在 in
参数中使用可变结构
private static double CalculateDistance(in Point3D point1, in Point3D point2) { double xDifference = point1.X - point2.X; double yDifference = point1.Y - point2.Y; double zDifference = point1.Z - point2.Z; return Math.Sqrt(xDifference * xDifference + yDifference * yDifference + zDifference * zDifference); }
如果没有语言保证,编译器必须在调用任何未标记为 readonly
修饰符的成员之前创建参数的临时副本。这些副本会降低性能,使得按值传递比按只读引用传递速度更快。
相反,如果距离计算使用不可变结构 ReadonlyPoint3D
,则不需要临时对象:
private static double CalculateDistance3(in ReadonlyPoint3D point1, in ReadonlyPoint3D point2 = default) { double xDifference = point1.X - point2.X; double yDifference = point1.Y - point2.Y; double zDifference = point1.Z - point2.Z; return Math.Sqrt(xDifference * xDifference + yDifference * yDifference + zDifference * zDifference); }