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

有些人可能已经忘记了:

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

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


当前回答

MSDN给出了答案: 在类和结构之间选择。

基本上,这个页面给你一个4项清单,并告诉你使用一个类,除非你的类型满足所有的标准。

不定义结构,除非 类型包含以下所有内容 特点: 它在逻辑上表示一个值,类似于基本类型 (整数,双精度,等等)。 实例大小小于16字节。 它是不可变的。 它不需要经常装箱。

其他回答

MSDN给出了答案: 在类和结构之间选择。

基本上,这个页面给你一个4项清单,并告诉你使用一个类,除非你的类型满足所有的标准。

不定义结构,除非 类型包含以下所有内容 特点: 它在逻辑上表示一个值,类似于基本类型 (整数,双精度,等等)。 实例大小小于16字节。 它是不可变的。 它不需要经常装箱。

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

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

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

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

我已经创建了两个。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 |

除了以上精彩的回答:

结构是值类型。

它们永远不能被设置为“无”。

设置一个结构= Nothing,将其所有的值类型设置为默认值。

✔️如果该类型的实例很小且通常存在时间很短,或者通常嵌入在其他对象中,请考虑定义一个结构而不是类。