Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/304.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
什么时候应该在C#中使用结构而不是类?_C#_Struct - Fatal编程技术网

什么时候应该在C#中使用结构而不是类?

什么时候应该在C#中使用结构而不是类?,c#,struct,C#,Struct,什么时候应该在C#中使用struct而不是class?我的概念模型是,当项目仅仅是一组值类型时,会使用结构。一种在逻辑上将它们结合在一起形成一个有凝聚力的整体的方法 我遇到了这些规则: 结构应该表示单个 价值观 结构应该有内存 占用空间小于16字节 之后不应更改结构 创造 这些规则有效吗?结构在语义上是什么意思 当需要值语义而不是引用语义时,请使用结构 编辑 不知道为什么人们会对此投反对票,但这是一个有效的观点,并且是在op澄清他的问题之前提出的,这是结构的最基本原因 struct Poin

什么时候应该在C#中使用struct而不是class?我的概念模型是,当项目仅仅是一组值类型时,会使用结构。一种在逻辑上将它们结合在一起形成一个有凝聚力的整体的方法

我遇到了这些规则:

  • 结构应该表示单个 价值观
  • 结构应该有内存 占用空间小于16字节
  • 之后不应更改结构 创造

这些规则有效吗?结构在语义上是什么意思

当需要值语义而不是引用语义时,请使用结构

编辑 不知道为什么人们会对此投反对票,但这是一个有效的观点,并且是在op澄清他的问题之前提出的,这是结构的最基本原因

struct Point
{
   public int x, y;

   public Point(int x, int y) {
      this.x = x;
      this.y = y;
   }
}
Point a = new Point(10, 10);
Point b = a;
a.x = 20;
Console.WriteLine(b.x);
如果需要引用语义,则需要类而不是结构

只要您:

  • 不需要多态性
  • 想要值语义,以及
  • 希望避免堆分配和相关的垃圾收集开销
    然而,需要注意的是,结构(任意大)的传递比类引用(通常是一个机器字)更昂贵,因此类在实践中可能会更快

    我认为一个好的第二近似值是“从不”


    如果你迫切需要PARF,考虑它们,但总是要测量。

    结构对于数据的原子表示是很好的,其中所述数据可以由代码复制多次。克隆一个对象通常比复制一个结构要昂贵,因为它涉及到分配内存、运行构造函数以及在处理完它后取消分配/垃圾回收。

    在需要使用-通常用于PInvoke显式指定内存布局的情况下,需要使用“结构”


    编辑:注释指出,可以将类或结构与StructLayoutAttribute一起使用,这当然是正确的。实际上,您通常会使用一个结构—它是在堆栈上分配的,而不是在堆上分配的,如果您只是将一个参数传递给一个非托管方法调用,这是有意义的。

    首先:互操作场景,或者当您需要指定内存布局时


    第二:当数据几乎与引用指针大小相同时。

    除了运行时直接使用的valuetypes和其他用于PInvoke目的的各种valuetypes之外,您只能在两种情况下使用valuetypes

  • 当您需要复制语义时
  • 当需要自动初始化时,通常在这些类型的数组中

  • 我使用structs打包或解包任何类型的二进制通信格式。这包括读取或写入磁盘、DirectX顶点列表、网络协议或处理加密/压缩数据


    在这种情况下,你列出的三条指导方针对我没有用处。当我需要以特定的顺序写出400字节的内容时,我会定义一个400字节的结构,我会用它应该具有的任何不相关的值来填充它,我会以当时最有意义的方式来设置它。(好吧,四百字节可能会很奇怪——但当我以编写Excel文件为生的时候,我处理的是多达40字节的结构,因为这就是一些BIFF记录的大小。)

    不,我不完全同意这些规则。它们是考虑性能和标准化的良好准则,但不考虑可能性。

    正如你在回答中看到的,有很多创造性的方法来使用它们。因此,这些指导原则必须是这样的,始终是为了性能和效率

    在本例中,我使用类以更大的形式表示真实世界的对象,使用结构表示具有更精确用途的较小对象。就像你说的,“一个更具凝聚力的整体。”关键词是“凝聚力”。类将是更多面向对象的元素,而结构可以具有其中一些特性,尽管规模较小。国际海事组织

    我经常在Treeview和Listview标记中使用它们,在这些标记中可以非常快速地访问常见的静态属性。我一直在努力以另一种方式获取这些信息。例如,在我的数据库应用程序中,我使用树状视图,其中有表、SP、函数或任何其他对象。我创建并填充我的结构,将其放入标记中,将其拉出,获取选择的数据,等等。我不会在课堂上这样做


    我会尽量保持它们的小型化,在单实例的情况下使用它们,并防止它们发生变化。谨慎的做法是注意内存、分配和性能。测试是非常必要的。

    我很少使用结构来处理事情。但那只是我。这取决于我是否需要该对象为空


    如其他答案所述,我将类用于现实世界的对象。我也有这样的想法,结构用于存储少量数据。

    我不同意原始帖子中给出的规则。以下是我的规则:

    1) 当存储在阵列中时,可以使用结构来提高性能。(另见)

    2) 在向C/C传递结构化数据或从C/C传递结构化数据的代码中需要它们++

    3) 除非需要,否则不要使用结构:

    • 它们的行为不同于赋值和赋值下的“普通对象”(引用类型) 作为参数传递时,可能导致意外行为; 如果查看代码的人不这样做,这尤其危险 不知道他们正在处理一个结构
    • 它们不能被继承
    • 将结构作为参数传递比类更昂贵

      • OP引用的源代码有一定的可信度……但是微软呢?对struct的使用持什么立场?我找了一些额外的,以下是我发现的:

        如果 a型
        int index = ...
        int id = peopleArray[index].Id;
        
        void Foo(ref Person person) {...}
        ...
        Foo(ref peopleArray[index]);
        
        class Point
        {
           public int x, y;
        
           public Point(int x, int y) {
              this.x = x;
              this.y = y;
           }
        }
        
        class Test
        {
           static void Main() {
              Point[] points = new Point[100];
              for (int i = 0; i < 100; i++) points[i] = new Point(i, i);
           }
        }
        
        struct Point
        {
           public int x, y;
        
           public Point(int x, int y) {
              this.x = x;
              this.y = y;
           }
        }
        
        Point a = new Point(10, 10);
        Point b = a;
        a.x = 20;
        Console.WriteLine(b.x);
        
        public struct MyPoint 
        {
            public int X; // Value Type
            public int Y; // Value Type
        }
        
        public class MyPointWithName 
        {
            public int X; // Value Type
            public int Y; // Value Type
            public string Name; // Reference Type
        }
        
        public struct IntStruct {
            public int Value {get; set;}
        }
        
        var struct1 = new IntStruct() { Value = 0 }; // original
        var struct2 = struct1;  // A copy is made
        var struct3 = struct2;  // A copy is made
        var struct4 = struct3;  // A copy is made
        var struct5 = struct4;  // A copy is made
        
        // NOTE: A "copy" will occur when you pass a struct into a method parameter.
        // To avoid the "copy", use the ref keyword.
        
        // Although structs are designed to use less system resources
        // than classes.  If used incorrectly, they could use significantly more.
        
        public class IntClass {
            public int Value {get; set;}
        }
        
        var class1 = new IntClass() { Value = 0 };
        var class2 = class1;  // A reference is made to class1
        var class3 = class2;  // A reference is made to class1
        var class4 = class3;  // A reference is made to class1
        var class5 = class4;  // A reference is made to class1  
        
        var struct1 = new IntStruct() { Value = 0 };
        var struct2 = struct1;
        struct2.Value = 1;
        // At this point, a developer may be surprised when 
        // struct1.Value is 0 and not 1
        
        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 |
        
        [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<C1> testListClass = new List<C1>();
                List<S1> testListStruct = new List<S1>();
                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;
                }
            }
        
        void AppendHello(StringBuilder builder)
        {
            builder.Append("hello");
        }