When should I use a struct rather than a class in C#?

前端 未结 28 3105
予麋鹿
予麋鹿 2020-11-21 11:55

When should you use struct and not class in C#? My conceptual model is that structs are used in times when the item is merely a collection of value types. A way to

28条回答
  •  不要未来只要你来
    2020-11-21 11:58

    I made a small benchmark with BenchmarkDotNet to get a better understanding of "struct" benefit in numbers. I'm testing looping through array (or list) of structs (or classes). Creating those arrays or lists is out of the benchmark's scope - it is clear that "class" is more heavy will utilize more memory, and will involve GC.

    So the conclusion is: be careful with LINQ and hidden structs boxing/unboxing and using structs for microoptimizations strictly stay with arrays.

    P.S. Another benchmark about passing struct/class through call stack is there https://stackoverflow.com/a/47864451/506147

    BenchmarkDotNet=v0.10.8, OS=Windows 10 Redstone 2 (10.0.15063)
    Processor=Intel Core i5-2500K CPU 3.30GHz (Sandy Bridge), ProcessorCount=4
    Frequency=3233542 Hz, Resolution=309.2584 ns, Timer=TSC
      [Host] : Clr 4.0.30319.42000, 64bit RyuJIT-v4.7.2101.1
      Clr    : Clr 4.0.30319.42000, 64bit RyuJIT-v4.7.2101.1
      Core   : .NET Core 4.6.25211.01, 64bit RyuJIT
    
    
              Method |  Job | Runtime |      Mean |     Error |    StdDev |       Min |       Max |    Median | Rank |  Gen 0 | Allocated |
    ---------------- |----- |-------- |----------:|----------:|----------:|----------:|----------:|----------:|-----:|-------:|----------:|
       TestListClass |  Clr |     Clr |  5.599 us | 0.0408 us | 0.0382 us |  5.561 us |  5.689 us |  5.583 us |    3 |      - |       0 B |
      TestArrayClass |  Clr |     Clr |  2.024 us | 0.0102 us | 0.0096 us |  2.011 us |  2.043 us |  2.022 us |    2 |      - |       0 B |
      TestListStruct |  Clr |     Clr |  8.427 us | 0.1983 us | 0.2204 us |  8.101 us |  9.007 us |  8.374 us |    5 |      - |       0 B |
     TestArrayStruct |  Clr |     Clr |  1.539 us | 0.0295 us | 0.0276 us |  1.502 us |  1.577 us |  1.537 us |    1 |      - |       0 B |
       TestLinqClass |  Clr |     Clr | 13.117 us | 0.1007 us | 0.0892 us | 13.007 us | 13.301 us | 13.089 us |    7 | 0.0153 |      80 B |
      TestLinqStruct |  Clr |     Clr | 28.676 us | 0.1837 us | 0.1534 us | 28.441 us | 28.957 us | 28.660 us |    9 |      - |      96 B |
       TestListClass | Core |    Core |  5.747 us | 0.1147 us | 0.1275 us |  5.567 us |  5.945 us |  5.756 us |    4 |      - |       0 B |
      TestArrayClass | Core |    Core |  2.023 us | 0.0299 us | 0.0279 us |  1.990 us |  2.069 us |  2.013 us |    2 |      - |       0 B |
      TestListStruct | Core |    Core |  8.753 us | 0.1659 us | 0.1910 us |  8.498 us |  9.110 us |  8.670 us |    6 |      - |       0 B |
     TestArrayStruct | Core |    Core |  1.552 us | 0.0307 us | 0.0377 us |  1.496 us |  1.618 us |  1.552 us |    1 |      - |       0 B |
       TestLinqClass | Core |    Core | 14.286 us | 0.2430 us | 0.2273 us | 13.956 us | 14.678 us | 14.313 us |    8 | 0.0153 |      72 B |
      TestLinqStruct | Core |    Core | 30.121 us | 0.5941 us | 0.5835 us | 28.928 us | 30.909 us | 30.153 us |   10 |      - |      88 B |
    

    Code:

    [RankColumn, MinColumn, MaxColumn, StdDevColumn, MedianColumn]
        [ClrJob, CoreJob]
        [HtmlExporter, MarkdownExporter]
        [MemoryDiagnoser]
        public class BenchmarkRef
        {
            public class C1
            {
                public string Text1;
                public string Text2;
                public string Text3;
            }
    
            public struct S1
            {
                public string Text1;
                public string Text2;
                public string Text3;
            }
    
            List testListClass = new List();
            List testListStruct = new List();
            C1[] testArrayClass;
            S1[] testArrayStruct;
            public BenchmarkRef()
            {
                for(int i=0;i<1000;i++)
                {
                    testListClass.Add(new C1  { Text1= i.ToString(), Text2=null, Text3= i.ToString() });
                    testListStruct.Add(new S1 { Text1 = i.ToString(), Text2 = null, Text3 = i.ToString() });
                }
                testArrayClass = testListClass.ToArray();
                testArrayStruct = testListStruct.ToArray();
            }
    
            [Benchmark]
            public int TestListClass()
            {
                var x = 0;
                foreach(var i in testListClass)
                {
                    x += i.Text1.Length + i.Text3.Length;
                }
                return x;
            }
    
            [Benchmark]
            public int TestArrayClass()
            {
                var x = 0;
                foreach (var i in testArrayClass)
                {
                    x += i.Text1.Length + i.Text3.Length;
                }
                return x;
            }
    
            [Benchmark]
            public int TestListStruct()
            {
                var x = 0;
                foreach (var i in testListStruct)
                {
                    x += i.Text1.Length + i.Text3.Length;
                }
                return x;
            }
    
            [Benchmark]
            public int TestArrayStruct()
            {
                var x = 0;
                foreach (var i in testArrayStruct)
                {
                    x += i.Text1.Length + i.Text3.Length;
                }
                return x;
            }
    
            [Benchmark]
            public int TestLinqClass()
            {
                var x = testListClass.Select(i=> i.Text1.Length + i.Text3.Length).Sum();
                return x;
            }
    
            [Benchmark]
            public int TestLinqStruct()
            {
                var x = testListStruct.Select(i => i.Text1.Length + i.Text3.Length).Sum();
                return x;
            }
        }
    

提交回复
热议问题