浅析C#中的结构体和类

类和结构是 .NET Framework 中的常规类型系统的两种基本构造。 两者在本质上都属于数据结构,封装着一组整体作为一个逻辑单位的数据和行为。 数据和行为是该类或结构的“成员”,它们包含各自的方法、属性和事件等

对于C/C++程序猿来说,结构体和类的区别很小。只是结构体的默认成员变量为public,类的默认成员变量为private。

但是对于C#来说,结构体和类有很多的不同。

首先来谈一谈为何需要结构体:
最基本的原因就是结构体有能力去管理、使用不同数据类型的组合。

.NET支持值类型和引用类型的概念,所有的C#内置类型中,除了string外均为值类型。

在C#中,结构体是值类型,类是引用类型。值类型可以减少对堆的管理、使用,减少垃圾回收,表现出更好的性能。但是值类型也有不好的一面,比如会涉及到装箱拆箱等操作。

下面定义一个结构体:

public struct Foo
{
    // Fields
    private string fooString;
    private int fooNumber;
    // Property
    public string FooString
    {
        get
        {
            return fooString;
        }
        set
        {
            fooString = value;
        }
    }
    // Method
    public int GetFooNumber()
    {
        return fooNumber;
    }
}

可以看到,结构体和类非常的相似。让我们更深层次的看看两者的不同。
1继承
结构体继承自System.ValueType,而类继承自System.Object。结构体不能继承其他的类或结构体,但是可以把结构体当做是接口。由于接口只是用于引用类型的操作,所以把结构体当成接口就会隐式的发生装箱操作。例如如下代码:
struct Foo : IFoo
{
int x;
}
IFoo iFoo = new Foo();

2构造
C#不允许结构体具有无参数的默认构造函数。原因是:对于值类型,编译器既不会生成默认构造函数,也不会调用默认构造函数。所以你不能这样初始化:

struct MyWrongFoo
{
    int x = 1;
}

但是你可以使用new:
Foo foo = new Foo();
这里需要注意的是,尽管使用了new操作,但是结构体分配在栈上,而不是堆上。更有趣的是,new操作没有调用无参数的构造函数。看看下面的代码:

struct Foo
{
    int x;
    public Foo(int x)
    {
        this.x = x;
    }
}
class FooTester
{
    [STAThread]
    static void Main(string[] args)
    {
        Foo f = new Foo();
    }
}

这里我重载了构造函数,就可以使用new了。
所以我们可以这样:
调用 new Foo()
调用重载的构造函数初始化
显示的设置每个值:
Foo foo;
foo.x = 0;

3析构
我们不能为结构体定义析构函数。

4只读关键字
对于引用类型,readonly关键字阻止你将引用指到其他对象,但是无法阻止你改变该对象的状体。
对于值类型来说,readonly关键字与C++中的const很像,阻止你改变对象的状态。

class MyReferenceType
{
    int state;
    public int State
    {
        get
        {
            return state;
        }
        set
        {
            state = value;
        }
    }
}
struct MyValueType
{
    int state;
    public int State
    {
        get
        {
            return state;
        }
        set
        {
            state = value;
        }
}
    }
class Program
{
    readonly MyReferenceType myReferenceType = new MyReferenceType();
    readonly MyValueType myValueType = new MyValueType();
    public void SomeMethod()
    {
        myReferenceType = new MyReferenceType(); // Compiler Error
        myReferenceType.State = 1234; // Ok
        myValueType = new MyValueType(); // Compiler Error
        myValueType.State = 1234; // Compiler Error
    }
}

总结:
为结构定义默认(无参数)构造函数是错误的。 在结构体中初始化实例字段也是错误的。 只能通过两种方式初始化结构成员:一是使用参数化构造函数,二是在声明结构后分别访问成员。 对于任何私有成员或以其他方式设置为不可访问的成员,只能在构造函数中进行初始化。

如果使用 new 运算符创建结构对象,则会创建该结构对象,并调用适当的构造函数。 与类不同,结构的实例化可以不使用 new 运算符。 在此情况下不存在构造函数调用,因而可以提高分配效率。 但是,在初始化所有字段之前,字段将保持未赋值状态且对象不可用。

当结构包含引用类型作为成员时,必须显式调用该成员的默认构造函数,否则该成员将保持未赋值状态且该结构不可用。 (这将导致编译器错误 CS0171。)

对于结构,不像类那样存在继承。 一个结构不能从另一个结构或类继承,而且不能作为一个类的基。 但是,结构从基类 Object 继承。 结构可实现接口,其方式同类完全一样。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一苇渡江694

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值