When should I use a struct instead of a class?

后端 未结 15 2129
臣服心动
臣服心动 2020-11-22 13:00

MSDN says that you should use structs when you need lightweight objects. Are there any other scenarios when a struct is preferable over a class?

Some people might ha

相关标签:
15条回答
  • 2020-11-22 13:06

    I have always used a struct when I wanted to group together a few values for passing things back from a method call, but I won't need to use it for anything after I have read those values. Just as a way to keep things clean. I tend to view things in a struct as "throwaway" and things in a class as more useful and "functional"

    0 讨论(0)
  • 2020-11-22 13:13

    I am surprised I have not read at any of the previous answer this, which I consider the most crucial aspect :

    I use structs when I want a type with no identity. For example a 3D point:

    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);
        }
    }
    

    If you have two instances of this struct you don't care if they are a single piece of data in memory or two. You just care about the value(s) they hold.

    0 讨论(0)
  • 2020-11-22 13:13

    Use a class if:

    • Its identity is important. Structures get copied implicitly when being passed by value into a method.
    • It will have a large memory footprint.
    • Its fields need initializers.
    • You need to inherit from a base class.
    • You need polymorphic behavior;

    Use a structure if:

    • It will act like a primitive type (int, long, byte, etc.).
    • It must have a small memory footprint.
    • You are calling a P/Invoke method that requires a structure to be passed in by value.
    • You need to reduce the impact of garbage collection on application performance.
    • Its fields need to be initialized only to their default values. This value would be zero for numeric types, false for Boolean types, and null for reference types.
      • Note that in C# 6.0 structs can have a default constructor that can be used to initialize the struct’s fields to nondefault values.
    • You do not need to inherit from a base class (other than ValueType, from which all structs inherit).
    • You do not need polymorphic behavior.
    0 讨论(0)
  • 2020-11-22 13:15

    If an entity is going to be immutable, the question of whether to use a struct or a class will generally be one of performance rather than semantics. On a 32/64-bit system, class references require 4/8 bytes to store, regardless of the amount of information in the class; copying a class reference will require copying 4/8 bytes. On the other hand, every distinct class instance will have 8/16 bytes of overhead in addition to the information it holds and the memory cost of the references to it. Suppose one wants an array of 500 entities, each holding four 32-bit integers. If the entity is a structure type, the array will require 8,000 bytes regardless of whether all 500 entities are all identical, all different, or somewhere between. If the entity is a class type, the array of 500 references will take 4,000 bytes. If those references all point to different objects, the objects would require an additional 24 bytes each (12,000 bytes for all 500), a total of 16,000 bytes--twice the storage cost of a struct type. On the other hand, of the code created one object instance and then copied a reference to all 500 array slots, the total cost would be 24 bytes for that instance and 4,000 for the array--a total of 4,024 bytes. A major savings. Few situations would work out as well as the last one, but in some cases it may be possible to copy some references to enough array slots to make such sharing worthwhile.

    If the entity is supposed to be mutable, the question of whether to use a class or struct is in some ways easier. Assume "Thing" is either a struct or class which has an integer field called x, and one does the following code:

      Thing t1,t2;
      ...
      t2 = t1;
      t2.x = 5;
    

    Does one want the latter statement to affect t1.x?

    If Thing is a class type, t1 and t2 will be equivalent, meaning t1.x and t2.x will also be equivalent. Thus, the second statement will affect t1.x. If Thing is a structure type, t1 and t2 will be different instances, meaning t1.x and t2.x will refer to different integers. Thus, the second statement will not affect t1.x.

    Mutable structures and mutable classes have fundamentally different behaviors, though .net has some quirks in its handling of struct mutations. If one wants value-type behavior (meaning that "t2=t1" will copy the data from t1 to t2 while leaving t1 and t2 as distinct instances), and if one can live with the quirks in .net's handling of value types, use a structure. If one wants value-type semantics but .net's quirks would cause lead to broken value-type semantics in one's application, use a class and mumble.

    0 讨论(0)
  • 2020-11-22 13:16

    It is an old topic, but wanted to provide a simple benchmark test.

    I have created two .cs files:

    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; }
    }
    

    Run benchmark:

    • Create 1 TestClass
    • Create 1 TestStruct
    • Create 100 TestClass
    • Create 100 TestStruct
    • Create 10000 TestClass
    • Create 10000 TestStruct

    Results:

    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 |
    
    0 讨论(0)
  • 2020-11-22 13:17

    when you don't really need behavior, but you need more structure than a simple array or dictionary.

    Follow up This is how I think of structs in general. I know they can have methods, but I like keeping that overall mental distinction.

    0 讨论(0)
提交回复
热议问题