MSDN 上说当你需要一个轻量级对象时应该选择 struct,说的含含糊糊,真的不知道有哪些场景下优先选择 struct 而不是 class。
可能有些人已经忘了。
我非常明白 struct 和 class 在技术上的不同,就是把不准什么场景下该使用它...
使用 class 的情况
继承/多态
的需求。使用 struct 的情况
如果你想使用基元类型 (int,long,byte ...)
如果你想精细的优化内存
如果 P/Invoke 必须传值类型。
如果你想减少 GC 的负载
如果没有 继承/多态
的需求。
Andrei Rînea:
申明一下,我没看过其他人的答案,我觉得最重要的方面是:当我需要一个无需 唯一标识
的类型时用 struct,比如说:3D
点。
public struct ThreeDimensionalPoint
{
public readonly int X, Y, Z;
public ThreeDimensionalPoint(int x, int y, int z)
{
this.X = x;
this.Y = y;
this.Z = z;
}
public override string ToString()
{
return "(X=" + this.X + ", Y=" + this.Y + ", Z=" + this.Z + ")";
}
public override int GetHashCode()
{
return (this.X + 2) ^ (this.Y + 2) ^ (this.Z + 2);
}
public override bool Equals(object obj)
{
if (!(obj is ThreeDimensionalPoint))
return false;
ThreeDimensionalPoint other = (ThreeDimensionalPoint)obj;
return this == other;
}
public static bool operator ==(ThreeDimensionalPoint p1, ThreeDimensionalPoint p2)
{
return p1.X == p2.X && p1.Y == p2.Y && p1.Z == p2.Z;
}
public static bool operator !=(ThreeDimensionalPoint p1, ThreeDimensionalPoint p2)
{
return !(p1 == p2);
}
}
值得注意的是,当用值类型替代引用类型后,当心 按值copy
的问题。
这是一个老话题了,我就提供一下 class 和 struct 的 benchmark 吧,有如下两个 .cs 文件。
public class TestClass
{
public long ID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
public struct TestStruct
{
public long ID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
运行 benchmark:
输出结果:
BenchmarkDotNet=v0.12.0, OS=Windows 10.0.18362
Intel Core i5-8250U CPU 1.60GHz (Kaby Lake R), 1 CPU, 8 logical and 4 physical cores
.NET Core SDK=3.1.101
[Host] : .NET Core 3.1.1 (CoreCLR 4.700.19.60701, CoreFX 4.700.19.60801), X64 RyuJIT [AttachedDebugger]
DefaultJob : .NET Core 3.1.1 (CoreCLR 4.700.19.60701, CoreFX 4.700.19.60801), X64 RyuJIT
| Method | Mean | Error | StdDev | Ratio | RatioSD | Rank | Gen 0 | Gen 1 | Gen 2 | Allocated |
|--------------- |---------------:|--------------:|--------------:|----------:|--------:|-----:|---------:|------:|------:|----------:|
| UseStruct | 0.0000 ns | 0.0000 ns | 0.0000 ns | 0.000 | 0.00 | 1 | - | - | - | - |
| UseClass | 8.1425 ns | 0.1873 ns | 0.1839 ns | 1.000 | 0.00 | 2 | 0.0127 | - | - | 40 B |
| Use100Struct | 36.9359 ns | 0.4026 ns | 0.3569 ns | 4.548 | 0.12 | 3 | - | - | - | - |
| Use100Class | 759.3495 ns | 14.8029 ns | 17.0471 ns | 93.144 | 3.24 | 4 | 1.2751 | - | - | 4000 B |
| Use10000Struct | 3,002.1976 ns | 25.4853 ns | 22.5920 ns | 369.664 | 8.91 | 5 | - | - | - | - |
| Use10000Class | 76,529.2751 ns | 1,570.9425 ns | 2,667.5795 ns | 9,440.182 | 346.76 | 6 | 127.4414 | - | - | 400000 B |
确实这是一个老话题了,我一般在讲究内存优化的场景下,优先考虑 struct,毕竟 struct 没有 object 的 同步块索引 + 方法表指针
,在 64bit 机器上,光这块开销就是 16byte,如果再放大千万倍那可不得了,其他的场景怎么搞都行。
Copyright© 2013-2020
All Rights Reserved 京ICP备2023019179号-8