MSDN说当需要轻量级对象时应该使用结构。在其他情况下,结构体比类更可取吗?

有些人可能已经忘记了:

结构可以有方法。 结构不能被继承。

我理解结构体和类之间的技术差异,我只是对什么时候使用结构体没有很好的感觉。


当前回答

当我想要将几个值组合在一起以从方法调用中传递内容时,我总是使用结构体,但在读取这些值之后,我将不需要将它用于任何事情。只是为了保持干净。我倾向于将struct中的东西视为“扔掉的”,而将类中的东西视为更有用和“功能性的”

其他回答

结构体在堆栈上而不是堆上因此它们是线程安全的,应该在实现传输对象模式时使用,你永远不想在堆上使用对象它们是易变的,在这种情况下你想使用调用堆栈,这是使用结构体的基本情况我对这里的答案感到惊讶,

我会在以下情况下使用结构体:

an object is supposed to be read only(every time you pass/assign a struct it gets copied). Read only objects are great when it comes to multithreaded processing as they don't requite locking in most cases. an object is small and short-living. In such a case there is a good chance that the object will be allocated on the stack which is much more efficient than putting it on the managed heap. What is more the memory allocated by the object will be freed as soon as it goes outside its scope. In other words it's less work for Garbage Collector and the memory is used more efficient.

我很惊讶我没有读到之前的答案,我认为这是最关键的方面:

当我想要一个没有标识的类型时,我使用结构体。例如一个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);
    }
}

如果你有这个结构体的两个实例,你不关心它们是内存中的单个数据还是两个。你只关心他们持有的价值。

Bill Wagner在他的书《effective c#》(http://www.amazon.com/Effective-Specific-Ways-Improve-Your/dp/0321245660)中有一章是关于这个的。他总结了以下原则:

类型数据存储的主要职责是什么? 它的公共接口是否完全由访问或修改其数据成员的属性定义? 你确定你的类型永远不会有子类吗? 您确定您的类型永远不会被多态处理吗? 如果你对4个问题都回答“是”,请使用结构体。否则,使用 类。

这是一个老话题,但希望提供一个简单的基准测试。

我已经创建了两个。cs文件:

public class TestClass
{
    public long ID { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

and

public struct TestStruct
{
    public long ID { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

运行基准:

创建一个TestClass 创建一个TestStruct 创建100个TestClass 创建100个TestStruct 创建10000个TestClass 创建10000 TestStruct

结果:

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 |