C# 结构体 struct

  C#中结构类型和类类型在语法上非常相似,他们都是一种数据结构,都可以包括数据成员和方法成员。

  结构和类的区别:

  1、结构是值类型,它在栈中分配空间;而类是引用类型,它在堆中分配空间,栈中保存的只是引用。

  2、结构类型直接存储成员数据,让其他类的数据位于对中,位于栈中的变量保存的是指向堆中数据对象的引用。

  C#中的简单类型,如int、double、bool等都是结构类型。如果需要的话,甚至可以使用结构类型结合运算符运算重载,再为C#语言创建出一种新的值类型来。

  由于结构是值类型,并且直接存储数据,因此在一个对象的主要成员为数据且数据量不大的情况下,使用结构会带来更好的性能。

一、声明结构的语法 - struct关键字

    public struct AddressBook
    { 
        //字段、属性、方法、事件
    }

  对于类而言,两个变量指向同一个对象的情况是存在的,因此对这样两个变量中的任意一个进行操作,起结果必然会影响另外一个,因为它们指向的是同一个对象。

  结构是值类型,,直接包含它自己的数据,每个结构都保存自己的一份数据,修改每一个结构的数据都不会对其他结构的数据造成影响。

二、给结构赋值

  如果从结构中创建一个对象,并将该对象赋给某个变量,则该变量包含结构的全部值。复制类型为结构的变量时,将同时复制该结构所持有的所有数据。由于结构不是引用类型,因此结构类型的变量不能被赋予null值。

复制代码
public class Program
    {
        static void Main(string[] args)
        {
            PersonStruct p1, p2;    //与类一样,但可以不new
            p1.Name = "张飞";
            p1.MobilePhone = "13553663108";
            p1.Birthday = DateTime.Now.AddYears(-10);

            p2 = p1;              //将p1的值赋给p2   //由于是值类型,因此赋值等于将全部值全部复制到p2的栈空间
            p2.Name = "关羽";     //然后修改p2的值看是否会影响p1
            Console.WriteLine(p1.Name);     //输出 张飞 没影响

            PersonClass p3 = new PersonClass();    
            p3.Name = "张飞";
            p3.MobilePhone = "13553663108";
            p3.Birthday = DateTime.Now.AddYears(-10);

            PersonClass p4 = new PersonClass();
            p4 = p3;              //将p3的值赋给p4   赋值后,由于是引用类型,因此两个对象指向的是同一个地址(堆空间)
            p4.Name = "关羽";     //然后修改p4的值看是否会影响p3
            Console.WriteLine(p3.Name);     //输出 关羽 没影响

            Console.ReadKey();
        }
    }

    public class PersonClass
    {
        public string Name;
        public string MobilePhone;
        public DateTime Birthday;
    }

    public struct PersonStruct
    {
        public string Name;
        public string MobilePhone;
        public DateTime Birthday;
    }
复制代码

  将一个结构变量赋值给另一个结构变量,就是把数据从一个结构复制到另一个结构。而类则不同,在类的变量之间,复制的是引用,而不是类数据。。因此当数据比较大的时候,这种数据复制机制会带来较大的开销。

三、构造函数

  结构类型可以有实例构造函数和静态构造函数,但不能有析构函数。

  1、实例构造函数

  结构类型都有一个预定义的,没有参数的构造函数,这点与类是一样的。此构造函数不允许删除和重定义,并且这个无参数的构造函数会一直存在,并不会因为定义了其他带参数的构造函数就消失,这一点和类不同。

   注意如果没有使用new运算符,是不可以使用数据成员的值(除非已显示地设置了该数据成员的值)和调用函数成员的(除非所有数据成员均已经被赋值)。

四、静态构造函数

  和类一样,结构类型也可以有静态构造函数,静态构造函数用于初始化静态数据成员。静态构造函数有如下特点:

  1、静态构造函数不能有访问修饰符和参数;

  2、静态构造函数不能访问实例成员;

  3、静态构造函数无法直接进行调用;

  结构和类的静态构造函数的触发规则不同,类的静态构造函数是在创建第一个实例或引用任何静态成员之前自动调用的,而结构的静态构造函数在以下情况调用:

  1、使用显式声明的构造函数进行初始化

  2、调用结构的方法或访问结构的静态数据成员(无论是读取还是赋值,访问实例数据成员不会触发CLR自动调用静态的构造函数)。

五、结构的多态和可继承性

  结构直接派生自System.ValueType,间接派生自System.Object,但结构是隐式密封的,不能作为基类在派生出其他的结构,也不能从类派生,但可以从接口派生。

  结构的特性:

  1、结构类型总是隐式密封的,因此在定义结构时不能使用sealed和abstract关键字;

  2、因为结构不能作为基类,结构的成员不能使用如下访问修饰符:protected和protected,internal;

  3、结构的函数成员不能声明为abstract和virtual,但是可以使用override关键字,用以覆写它的基类System.ValueType中的方法。

六、结构的装箱与拆箱

  结构是值类型,因此当它被转换为object类型时,或者它所实现的接口类型的时候,就会执行装箱操作;同样,当执行相反操作的时候,就会执行拆箱操作。

七、结构和类的对比

                       结构                    类
  数据类型                值类型                  引用类型
  是否必须使用new运算符实例化      否                    是
  是否可声明无参数的构造函数       否                    是
  数据成员可否在声明的同时初始化     声明为const或static可以,数据成员不可以  可以
  直接派生自什么类型           System.ValueType             有
  是否有析构函数             无                    有
  可否从类派生              否                    可以
  可否实现接口              可以                   可以
  实例化时在栈还是在堆分配内存      栈                    堆,栈中保存引用
  该类型的变量可否被赋值为null       否                    可以
  可否定义私有的无参构造函数       否                    可以
  是否总有一个默认的无参构造函数       是                    否

  无论结构使用预定义的、无参数的构造函数,还是使用用户定义的、有参数的构造函数进行初始化,都会初始化结构的数据成员。不过预定义的,无参的会将数值型初始化为默认值,引用类型初始化为null;而用户自定义的初始化策略对个成员进行初始化。因此结构类型的数据成员不允许在声明是显式初始化。

八、性能

  因为结构是值类型,因此在为结构分配内存,或者当结构超出了作用域被删除时,性能会非常好,因为他们将内联或者保存在堆栈中。当把一个结构类型的变量赋值给另一个结构时,对性能的影响取决于结构的大小,如果结构的数据成员非常多而且复杂,就会造成损失,接下来使用一段代码来说明这个问题。

  结构和类的适用场合分析:

  1、当堆栈的空间很有限,且有大量的逻辑对象时,创建类要比创建结构好一些;

  2、对于点、矩形和颜色这样的轻量对象,假如要声明一个含有许多个颜色对象的数组,则CLR需要为每个对象分配内存,在这种情况下,使用结构的成本较低;

  3、在表现抽象和多级别的对象层次时,类是最好的选择,因为结构不支持继承。

  4、大多数情况下,目标类型只是含有一些数据,或者以数据为主。

 

来自:http://www.cnblogs.com/kissdodog/archive/2013/05/11/3072832.html

<think>好的,我现在需要帮助用户了解如何在C#中定义和使用struct结构体。首先,我得回忆一下C#结构体的基本知识。结构体是值类型,通常用于轻量级的数据结构,这和类不同,类是引用类型。用户可能想知道定义结构体的语法和注意事项。 首先,定义结构体的基本语法。应该用struct关键字,后面跟结构体名称,然后在大括号里定义成员。比如public struct Point { public int X; public int Y; }。这里需要提到结构体可以包含字段、方法、属性,甚至构造函数,但需要注意不能有无参构造函数,因为编译器会自动生成一个,用户不能自定义。这点在引用[3]中提到过,所以需要引用。 接下来是使用结构体的例子。比如如何实例化,可以new也可以不用new。比如Point p1 = new Point(10, 20); 或者Point p2; p2.X = 5;。这里要说明两种方式的区别,特别是未使用new时,所有字段必须初始化后才能使用。 然后需要提到结构体的特点,比如值类型,分配在栈上,适合小数据结构。还有结构体不能继承,但可以实现接口。这些是结构体和类的主要区别,可以引用引用[2]中的准则,帮助用户决定何时使用结构体。 还要注意构造函数的部分。结构体可以有带参数的构造函数,但必须初始化所有字段。比如public Point(int x, int y) { X = x; Y = y; }。这里要强调必须全部初始化,否则会编译错误。这一点引用[3]也提到了,所以需要标注引用。 最后,可能需要比较结构体和类的区别,帮助用户理解适用场景。比如结构体适合轻量、不可变的数据,而类适合更复杂的对象。同时提醒用户结构体传递时是复制值,可能影响性能,所以不宜过大。 用户还可能关心结构体的性能优势和限制,比如作为值类型在内存中的处理方式,以及装箱拆箱的问题。但可能这些问题属于进阶内容,用户的问题主要是定义和使用,所以可能放在相关问题里更合适。 总结一下,回答的结构应该是先定义语法,再示例使用,然后讨论注意事项和特点,最后引用相关参考资料。确保覆盖用户的问题,同时提供足够的信息帮助他们正确使用结构体。</think>在C#中,结构体struct)是一种值类型数据结构,适合封装小型数据组。以下是定义和使用的关键点: ### 一、定义结构体 使用$struct$关键字定义,可包含字段、方法、属性和构造函数: ```csharp public struct Point { public int X; //字段定义 public int Y; //带参数构造函数(必须初始化所有字段) public Point(int x, int y) { X = x; Y = y; } //方法定义 public void Print() => Console.WriteLine($"({X},{Y})"); } ``` ▲ 注意:结构体不能声明无参构造函数[^3],默认构造函数自动初始化所有字段为默认值 ### 二、使用结构体 #### 1. 实例化方式 ```csharp //方式1:使用new(调用构造函数) Point p1 = new Point(10, 20); //方式2:直接声明后赋值 Point p2; p2.X = 5; //必须初始化所有字段后才能使用 p2.Y = 8; ``` #### 2. 值类型特性 ```csharp Point a = new Point(3,4); Point b = a; //值拷贝 b.X = 100; //修改b不影响a Console.WriteLine(a.X); //输出3 ``` #### 3. 实现接口 ```csharp public interface IShape { double Area(); } public struct Rectangle : IShape { public double Width; public double Height; public double Area() => Width * Height; } ``` ### 三、注意事项 1. **内存分配**:结构体存储在栈内存,适合包含少于16字节的数据[^2] 2. **不可变性**:推荐将结构体设计为不可变类型(readonly struct) 3. **性能考量**:频繁装箱操作会影响性能,需避免大规模结构体传递 4. **继承限制**:不能作为基类,但可实现多个接口 ### 四、适用场景 - 坐标点、颜色值等轻量数据结构 - 需要高频创建/销毁的小型对象 - 避免垃圾回收开销的实时系统 - 数据包传输等值语义场景[^1] ```csharp // 实际应用示例:RGB颜色结构 public struct RGBColor { public byte R; public byte G; public byte B; public RGBColor(byte r, byte g, byte b) => (R,G,B) = (r,g,b); public string ToHex() => $"#{R:X2}{G:X2}{B:X2}"; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值