您的位置:首页 > 编程语言 > C#

浅析C#中的结构体和类

2015-08-20 08:49 281 查看
类和结构是 .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 继承。 结构可实现接口,其方式同类完全一样。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: