Fork me on GitHub

Effective C# 条款1

属性的优点:

  1. 遵循面向对象的原则
  2. 具有弹性

1. 1  遵循面向对象的原则

  属性在使我们可以将数据成员暴露为公有接口的同时,还为我们提供了在面向对象环境中所期望的封装。从表面看起来像是数据成员,但内部却是以方法实现。

 

 
public class TestClass
{
//成员变量
public string Name;
}

 

  

public class TestClass
{
//属性
public string Name { get; set; }
}

 

TestClass testClass = new TestClass();

testClass.Name
= "TestClass";

  这段代码非常简洁和直观。有人据此就认为以后如果有需要,再将 TestClass 类的数据成员 Name 替换为属性OK了,而使用TestClass类型的代码无需做任何改变。这种说法从某种程度上来讲是对的。

  属性在被访问的时候和数据成员看起来没有什么差别。这正是 C#引入新的属性语法的一个目标。但属性毕竟不是数据,访问属性和访问数据产生的是不同的 MSIL。在程序编译后,编译器在把程序编译成为MSIL时,会自动把属性中的get/set编译成为两个方法,所以属性能够获得函数的全部好处。但实际区别我们可以通过如下的MSIL分析可知成员变量和属性是存在区别的。

图1 TestClass类编译后的MSIL 

  通过图1我们没有找到Name属性,取而代之的是两个get_Name / set_Name方法,充分说明了属性是通过方法的方式调用。

图2成员变量MSIL

 

图3属性MSIL

 

  大家注意尽管访问属性和访问数据成员使用的是同样的 C#源代码,但是 C#编译器却将它们转换为不同的IL代码。

  换句话说,虽然属性和数据成员在源代码层次上是兼容的,但是在二进制层次上却不兼容。这意味着如果将一个类型的公有数据成员改为公有属性,那么我们必须重新编译所有使用该公有数据成员的C#代码。

1.2 具有弹性

  使用属性在修改上也比成员变量更具有弹性,例如程序要判断成员变量是否为空时,我们就需在代码某处加上判断逻辑,而属性我们只需在属性上加上判断逻辑,省去了烦心查找要加逻辑的地方。

private string _name;
public string Name
{
get
{
if (_name == null)
return string.Empty;
return _name;
}
set
{
_name
= value;
}
}

  由于属性是采用方法来实现的,因此为它们添加多线程支持就更加容易——直接在get和 set方法中提供同步数据访问控制即可:

public string Name

{

get

{

lock( this )

{

return _name;

}

}

set

{

lock( this )

{

_name
= value;

}

}

}

经验总结:

  只要打算将数据暴露在类型的公有接口或者受保护接口中,我们都应该使用属性来实现。对于具有序列或者字典特征的类型,则应该采用索引器。

posted @ 2011-04-03 13:59  JK_Rush  阅读(817)  评论(0编辑  收藏  举报