属性(property) VS 数据成员(field)

对于可访问的数据成员(指的是类外部可以访问),就是指在类中,用public修饰的简单的公共变量。

而属性,要比这个复杂得多,同时,自从1.0以来,C#对属性进行了一系列的增强,属性愈发强大。

 

1. 从概念上讲

属性是对私有字段的访问进行封装,它提供了对私有字段灵活的读、写和计算操作。在C#中,我们通过get和set访问器来实现对属性的读和写操作。

 

2. 从本质上来说

属性让我们可以创建出类似于数据访问,也就是说,我们对属性的操作,跟对数据成员的操作时很类似的。但是,属性事实上是一个方法。

假设我们有一个Address的类如下:

 

public class Address
    {
        public string State { get; set; }

        public string City;
    }

 

其中State是属性,而City是公开的数据成员,如果我们进行如下调用:

 

            Address address = new Address();
            address.State = "NY";//property
            address.City = "New York";//field
            Console.WriteLine("I live in :"+address.State+" "+address.City);
            Console.ReadLine();
 
通过查看IL代码,我们可以发现,对于address.State=”NY”的操作,实际上是调用一个叫做set_State(string) 的方法,同样的,对于读取操作的address.State,实际上是调用get_State() 方法:
 
//address.State = "NY";对应的IL代码
callvirt instance void ConsoleApplicationTest.Entity.Address::set_State(string) 
 
//address.State对应的IL代码:
callvirt instance string ConsoleApplicationTest.Entity.Address::get_State() 
 
//address.City = "New York";对应IL代码
ldstr "New York"
stfld string ConsoleApplicationTest.Entity.Address::City
 
//address.City对应的IL嗲吗
ldfld string ConsoleApplicationTest.Entity.Address::City
 
也就是说,属性能够以方法调用的形式访问或修改内部数据,成员函数中可以实现的功能均可以在属性中实现。
 
 
3. 灵活性
 
属性相对于普通的数据成员来说,具有跟高的灵活性。特别是当我们有新的需求或行为时。
假设我们有一个Customer类,如下:
 
public class Customer
    {
        private string name;
        public string Name
        {
            get { return name; }
            set { name = value; }
        }
    }

 

 

但是,我们可能很快就会有这样的需求,客户的名字是不能赋值为空的,对于属性,我们可以很方便的修改如下:

public class Customer
    {
        private string name;
        public string Name
        {
            get { return name; }
            set
            {
                if(string.IsNullOrEmpty(name))throw new ArgumentException("Name cannot be blank","Name");
                name = value;
            }
        }
    }

 

而对于使用属性的地方,我们根本不用去修改它。

试想一下,如果我们不是使用属性,而是使用字段,天晓得我们需要修改多少地方呢?

同时,我们还可以在get和set中封装一些逻辑,从而保证数据的读写是安全的,而公有的数据成员,我们可能会产生一些不安全的操作,如数组越界等。

 

4. 读和写操作的访问权限的限制

对于属性,我们可以设定其读和写设定不同的访问权限,具体方法就是通过在get和set前面加上protected或public等。

 

5. 将数据成员改成属性

虽然属性和数据成员在使用上是兼容的,但是在二进制层面却大相径庭。如果我们将某个数据成员改成属性,那么就必须重新编译所有用到该公有数据成员的代码。

 

6. 性能

数据成员访问虽然在性能上会更快一些。但是,JIT编译器将内联一些方法调用,包括属性访问器。当JIT编译器内联了属性访问器时,两者的访问效率基本就可以持平了。即使某个属性访问器没有被内联,属性相对于数据成员访问,仅仅多了一个方法调用而已,因此,二者的性能差别也是微乎其微的。

 

7. 书写上

也许你会说,属性的书写较数据成员更麻烦,事实上,在VS的IDE中,键入prop,然后按TAB建,便会自动输出public TYPE Type { get; set; },然后你只需要将TYPE和Type改成实际需要的就可以了。书写起来一点也不麻烦。

 

因此,无论何时,需要在类型的公有或保护接口中暴露数据,我们都应该使用属性(property),而不是数据成员(field)。这也是微软推荐的做法。

posted @ 2012-05-19 17:36  Xiao Tian  阅读(742)  评论(2编辑  收藏  举报