关于结构和类的区别

本文总结了结构和类之间的15个关键区别,包括类型、大小、继承能力、构造函数、多态性等方面。

 关于结构和类的区别其实是老生常谈,不过本文总结得较为全面,所以翻译过来给大家共享。

总结起来,两者共有如下区别:

1、结构是值类型,类则是引用类型。因此前者是放在栈(Stack)里,后者则仅仅是将引用地址存放在栈里,而具体的值则存放在堆(heap)里。如下图所示:

2、据第1点可以得出结论,那就是类对象通常用来传递大数据,而结构对象则用来传递小数据。
3、类可以被继承,而结构则不支持。
4、结构对象不能像类对象一样赋值为null。
5、结构不能像类一样定义析构器。
6、结构不能像类一样定义为抽象的。
7、在结构中不能重写方法,除非是object类型的如下方法:

  • Equals()
  • GetHashCode()
  • GetType()
  • ToString()

 

 

若要让结构具有多态特性,可以让其实现接口。
8、在类中定义的事件是线程安全的,而结构则不是。
9、结构总是具有一个默认的公共无参构造函数,但却不能像类一样定义私有的无参构造函数(结构也不能再定义公共的无参构造函数,这与类不相同):
    struct Me
    {
        private Me() // compile-time error
        {
        }
    }
    
    class
Me
    {
        private Me() // runs Ok{
    }

10、类中的静态构造函数会被调用,而结构却不能。因此在结构中定义的静态构造函数,虽然可以编译通过,但却没有价值:

    struct myStructure
    {
        static myStructure()
        {
            Console.WriteLine("This is me a structure");
        }
    }
    class myClass

    {
        static myClass()
        {
            Console.WriteLine("This is me a class");
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
           myStructure s = new myStructure();//Nothing happen
           myClass c = new myClass();//Will out put This is me a class
           Console.Read();
        }
    }

 

11、结构不能像类一样定义volatile字段。volatile字段主要用于并发,它相当于方法体的lock。
12、可以对结构类型使用sizeof,对类则不行。
13、类的字段会被自动初始化为0/false/null,而结构则不能。
14、在结构中不能直接对字段初始化,而类则可以。
    struct myStructure
    {
        public string x = 2;//Not allowed
    }
    class myClass
    {
        public string x = 2; //Allowed
    }

15、结构和类对于System.Object.Equals()方法的体现是不相同的。例如定义这样的结构和类:
    struct StructurePerson
    {
        public string FirstName;
        public string LastName;
    }
    class ClassPerson
    {
        public string FirstName;
        public string LastName;
    }

如果运行如下的代码:

    class Program
    {
        static void Main(string[] args)
        {
            StructurePerson strX = new StructurePerson();
            strX.LastName = "Bejaoui";
            strX.FirstName = "Bechir";
            StructurePerson strY = new StructurePerson();
            strY.LastName = "Bejaoui";
            strY.FirstName = "Bechir";

            if (strX.Equals(strY))
            {
                Console.WriteLine("strX = strY");
            }
            else
            {
                Console.WriteLine("strX != strY");
            }//This code displays strX = strY

            ClassPerson clsX = new ClassPerson();
            clsX.LastName = "Bejaoui";
            clsX.FirstName = "Bechir";
            ClassPerson clsY = new ClassPerson();
            clsY.LastName = "Bejaoui";
            clsY.FirstName = "Bechir";

            if (clsX.Equals(clsY))
            {
                Console.WriteLine("clsX = clsY");
            }
            else
            {
                Console.WriteLine("clsX != clsY");
            }//This code displays clsX != clsY
            Console.Read();
        }
    }

 

由于结构类型是值类型,因而Equals()方法比较的是两个对象的值是否相等,如果相等则返回true;而类类型为引用类型,Equals()方法比较的是二者的引用地址(即指针)是否相等。很显然,clsX和clsY是两个不同的对象,它们在栈的地址是不相等的。如果修改代码如下:

            ClassPerson clsX = new ClassPerson();
            clsX.LastName = "Bejaoui";
            clsX.FirstName = "Bechir";
            ClassPerson clsY = clsX;
            if (clsX.Equals(clsY))
            {
                Console.WriteLine("clsX = clsY");
            }
            else
            {
                Console.WriteLine("clsX != clsY");

            }//This code displays clsX = clsY

 


由于是直接将clsX赋值给clsY,因此两个对象的引用地址相等,Equals()方法返回true。

 

其实对于值类型和引用类型的相等性比较,是一个比较复杂的问题。例如我们可以通过重写Equals()方法增强或修改比较逻辑。重写Equals()方法还必须重写GetHashCode()方法。对于引用类型,还可以使用静态方法ReferenceEquals()方法。此外,还可以重载操作符==。另外,对于String对象,则比较特殊,因为它使用了Immutable模式。虽然String类型是引用类型,但如果直接定义的两个String对象的值相同,由于采用了Immutable模式的原因,这两个对象其实是同一个对象,引用地址是相同的。因此不仅动态方法Equals()返回的是true,且静态方法ReferenceEquals()返回的也是true。

在 C# 中,结构structclass)都是用于创建自定义型的构造,但它们存在显著区别,这些区别影响着使用场景性能表现: 1. **基本型分**:是引用型,而结构体是值型[^1]。 2. **内存分配**:结构体分配在栈上,而分配在堆上。当结构体变量被赋值给另一个变量时,实际的数据会被复制,而不是引用,这意味着对一个结构体变量的修改不会影响另一个结构体变量;而变量赋值时,复制的是引用,对一个变量的修改可能会影响另一个引用相同对象的变量[^3]。 3. **继承性**:结构体不能从其他结构体或继承,但是可以实现接口;而可以继承其他实现接口,支持多态等面向对象特性[^3]。 4. **性能表现**:由于结构体在栈上分配内存,在处理小型数据对象时,结构体通常比更高效,特别是在大量创建销毁对象时。不过,只要把结构作为参数来传递或者把一个结构赋值给另一个结构结构的所有内容就被复制,会有性能损失;而传递时只复制引用。若把结构作为参数传递给方法,将其作为 ref 参数传递可避免性能损失,但要注意被调用的方法可以改变结构的值[^2][^3][^4]。 5. **使用场景**:结构体可以包含方法、属性、构造函数等,但这些方法通常应与结构体的数据紧密相关,不适合封装复杂的行为或状态;而更适合处理复杂的行为状态封装[^2]。 6. **构造函数**:每个结构体都有一个隐式的无参构造函数,该构造函数会将所有字段初始化为其默认值,不能定义显式的无参构造函数,但可以定义有参数的构造函数;可以定义显式的无参有参构造函数[^3]。 7. **初始化要求**:在使用结构体实例之前,必须初始化所有字段,否则会导致编译错误;的实例初始化要求相对灵活[^3]。 以下是结构的简单定义示例: ```csharp // 结构体定义 public struct Point { public int X { get; set; } public int Y { get; set; } public Point(int x, int y) { X = x; Y = y; } public void Display() { Console.WriteLine($"X: {X}, Y: {Y}"); } } // 定义 public class PointClass { public int X { get; set; } public int Y { get; set; } public PointClass(int x, int y) { X = x; Y = y; } public void Display() { Console.WriteLine($"X: {X}, Y: {Y}"); } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值