也许由于C#一些特性的原因,结构体(struct)很少使用(但是在 System.Drawing.Point、Size、Color这几个依然是用的结构体!),似乎都快被人们遗忘了,甚至于有些新手会不知道在C#中有结构体的存在 ,这几天刚好复习了下,于是便想拿出来和大家分享下。

class Program
{
static void Main(string[] args)
{
Person person
= new Person();
Console.WriteLine(person.Age);
Console.WriteLine(person.Name);
MyPerson person1
= new MyPerson();
Console.WriteLine(person1.Age);
Console.WriteLine(person1.Name);
}
}
//结构体
public struct Person
{
public Person(string name, int age):this()
{
this.Name = name;
this.Age = age;

}
public string Name { get; set; }
public int Age { get; set; }
public void Show()
{
Console.WriteLine(
"我的名字叫做{0},今年{1}岁了",Name,Age);
}
}
//
public class MyPerson
{
public MyPerson() { }
public MyPerson(string name,int age)
{
this.Age = age;
this.Name = name;
}
public string Name { get; set; }
public int Age { get; set; }
public void Show()
{
Console.WriteLine(
"我的名字叫做{0},今年{1}岁了", Name, Age);
}
}

通过上面的代码,大家可以看出,在C#中结构体和类似乎就是一样的, 结构与类共享大多数相同的语法,但结构比类受到的限制更多。

具体的我们慢慢来说。

    首先,C#中结构体和类的最大区别就是结构体是值类型,而类是引用类型。也就是说当实例化结构体的时候是在栈上拷贝了结构体的一个副本,而类实例化的时候是在栈上分配一个指针指向了堆中分配的空间。

    其次,在结构体中,除非字段被声明为conststatic,否则是无法初始化的。

    结构体不能声明默认构造函数(没有参数的构造函数)或析构函数。这里能细说下,细心的网友可能发现我上面定义的结构体和类中各自的构造函数是稍微有点不同的,在结构体的构造函数后面还加了个:this()

让我们来做个试验,去掉:this(),然后重新编译下,结果编译器报:

“错误 1在控制返回到调用程序之前,自动实现的属性“结构体的演示.Person.Age”的支持字段必须完全赋值。请考虑从构造函数初始值设定项中调用默认构造函数。

  错误   2 在控制返回到调用程序之前,自动实现的属性“结构体的演示.Person.Name”的支持字段必须完全赋值。请考虑从构造函数初始值设定项中调用默认构造函数。    

  错误   3 在给“this”对象的所有字段赋值之前,无法使用该对象。”

是不是会感到很纳闷,我明明也是定义了有参数的构造函数,然后和类一样想初始化结构体中的属性,结果却报错了!

嘿嘿,别急,首先我们要明白在C#的结构体中使用前都必须赋初值.明白这点后我们先将构造函数删除后生成exe后用强大的.NET反编译工具Reflector来看看到底底层是怎么实现的.

[StructLayout(LayoutKind.Sequential)]
public struct Person
{
[CompilerGenerated]
private string <Name>k__BackingField;
[CompilerGenerated]
private int <Age>k__BackingField;
public Person(string name, int age);
public string Name { [CompilerGenerated] get; [CompilerGenerated] set; }
public int Age { [CompilerGenerated] get; [CompilerGenerated] set; }
public void Show();
}


Expand Methods

看到 

    [CompilerGenerated]

    private string <Name>k__BackingField;

    [CompilerGenerated]

    private int <Age>k__BackingField;

这两个了吧 ,其实是IL将属性自动转换成了字段了,但是这两个字段我们是没有初始化的,就是没有赋初值的,所以我们是无法使用上述样子的构造函数!

而当我们把:this()加上,生成后在通过Reflector来看看:

public Person(string name, int age)
{
this = new Person();
this.Name = name;
this.Age = age;
}

发现多了个this = new Person();从中我们也能看出一点端倪,C#中的结构体之所以不能定义无参构造函数是为了避免对其中自带的构造函数进行重写,而自带的构造函数其实是用来初始化结构体中的各个成员的!

    结构不能从类或其他结构继承。

    结构在赋值时进行复制。将结构赋值给新变量时,将复制所有数据,并且对新副本所做的任何修改不会更改原始副本的数据。

 

    与类不同,结构的实例化可以不使用 new 运算符。

但是在使用时不用new运算符的话,必须要如下面的使用:

 

static void Main(string[] args)
{
Person person ;
person.age
= 17;
person.name
= "小亮";
Console.WriteLine(person.age);
Console.WriteLine(person.name);

}
}
//结构体
public struct Person
{
public string name;
public int age;

}

而不能像如下一样使用:

  

 static void Main(string[] args)
        {
            Person person;
            person.Age = 17;
            person.Name = "小亮";
            Console.WriteLine(person.Age);
            Console.WriteLine(person.Name);
        
        }
    }
    //结构体
    public struct Person
    {
       
        public string Name { get; set; }
        public int Age { get; set; }
        public Person(string name, int age):this()
        {
            this.Name = name;
            this.Age = age;

        }
    }

不然,依然会因为没有调用默认结构体的构造函数而没有初始化结构体属性中最终生成的私有字段而报错的!

⑦ 一个结构不能从另一个结构或类继承,而且不能作为一个类的基。所有结构都直接继承自 System.ValueType,后者继承自 System.Object

⑧ 结构可以实现接口。

⑨ 最后说说自己对于什么时候使用结构体而不使用类的一些见解:

    结构体适合一些小型数据结构,这些数据结构包含的数据以创建结构后不修改的数据为主;

    定义的时候不会用到面向对象的一些特性;

        结构体在不发生装箱拆箱的情况下性能比类类型是高很多的.

     酝酿了几天的文章终于写完了。上述仅是个人的一些见解,可能存在着错误,还希望园子里各位前辈多多指教。

 

作者: ωǒじ落叶 发表于 2011-08-22 20:14 原文链接

推荐.NET配套的通用数据层ORM框架:CYQ.Data 通用数据层框架
新浪微博粉丝精灵,刷粉丝、刷评论、刷转发、企业商家微博营销必备工具"