All articles| All Pictures| All Softwares| All Video| Go home page| Write articles| Upload pictures

Reading number is top 10 articles
叩开C#之门系列之C#与面向对象编程语言_[Asp.Net教程]
asp.net2.0内置Application对象的应用
visual c++程序中的文件类型
利用Cache限制页面频繁请求(最少要等N秒)_[Asp.Net教程]
IIS6的PHP最佳配置方法_[PHP教程]
学习SQL2005当中的例子_mssql学习_编程技术
PHP实例:PHP和JS实现交互的一个例子_[PHP教程]
初学,ASP.NET,AJAX,(三):使用,UpdatePanel_[Asp.Net教程]
PHP应用技巧小总结:几个有用的小技巧_php资料_编程技术
.NET字符串的特点,正则表达式在其中如何运用_.net资料_编程技术
Reading number is top 10 pictures
玩手机对身体不好
9.3阅兵全景图4-陸海空现代化兵种方阵梯队
世界各国15岁的MM有什么不同
奇趣的世界记录1
中国女孩大胆自拍,显露完美身材2
深圳的风光
天安门景物系列(一)
中国文革时期的色情图片2
新版武松打虎
中国处女图鉴2
Download software ranking
美女游泳记
Unix video tutorial15
WebService在.NET中的实战应用教学视频 → 第4集
Take off clothes to survival
Love the forty days
Unix video tutorial4
Unix video tutorial2
Tram sex maniac 2 (H) rar bag7
Proficient in Eclipse
SQL2000 For 4IN1
delv published in(发表于) 2014/1/6 9:07:01 Edit(编辑)
C#箴言之用属性来访问类的私有成员_[Asp.Net教程]

C#箴言之用属性来访问类的私有成员_[Asp.Net教程]

C#箴言之用属性来访问类的私有成员_[Asp.Net教程]

在程序中,难免要访问某个对象的私有成员。那么以前实现这类功能的方法有两种,第一种方法最简单,就是把成员访问符从“private”改为“public”即可;而另一个就是提供公有的成员访问函数来进行访问。那么现在用C#编写程序,就不再需要采用前面所说的两种方法了,而直接使用属性来完成。

  首先来看看三种方法的如何实现以及调用的,这里用一个例子来说明,即访问“EmployeeInfo”类的私有成员strName,具体如下表格所示。


private string strName;
访问方法
修改成员访问符
修改:
private string strName;
为:
public string strName;
EmployeeInfo empNew...;
string strNameValue = empNew.strName;
empNew.strName = "me";
公有成员函数
增加如下两个成员函数:
public string getName()
{
 return strName;
}

public void setName( string Name )
{
 strName = Name;
}
EmployeeInfo empNew...;

string strNameValue = empNew.getName();

empNew.setName( "me" );
属性
增加如下属性:
public string Name
{
 get{ return strName;}
 set{ strName = value; }
}

EmployeeInfo empNew...;
string strNameValue = empNew.Name;
empNew.Name = "me";

  那么这三种方法有什么区别呢,用如下的表格,可以更好的说明三者的区别。


类的封装性
代码安全性
代码繁琐性
代码效率
修改成员访问符
破坏类的封装
存在潜在危险
简便
最高
公有成员函数
没有破坏
安全
繁琐,而且调用不直接
最低
属性
没有破坏
安全
简便
仅次于第一种方法
    (备注:这里用红色表明每一子项中最不好的)

  因此可以看出使用属性不但没有破坏类的封装性,没有减弱代码的安全性,而且和第一种方法一样简便,只是在效率方面要略低于第一种方法。但总体看来,在C#中用属性来访问类的私有成员是不二的选择。

  不过对于使用属性,以及如上表格所说的,难免会有人产生如下一些疑问。

  疑问一:就是用属性是否能达到成员函数那样的效果,即完成复杂的代码操作。

  其实属性的底层实现是借助于成员函数,只不过这部分转换是由系统帮忙做的,所以在编写属性的时候,可以像编写成员函数一样,即在成员函数中所能写的代码片断,完全可以在属性中套用。下面就贴出属性所转换的微软中间语言(MSIL)代码。


.property instance string Name()
{
 .get instance string NameSpace.EmployeeInf:get_Name()
 .set instance void NameSpace.EmployeeInf:set_Name(string)
}// end of property EmployeeInf:Name

.method public hidebysig specialname instance string get_Name() cil managed
{
 ...
}// end of method EmployeeInf:get_Name

.method public hidebysig specialname instance void set_Name(string 'value') cil managed
{
 ...
}// end of method EmployeeInf:set_Name

  如上就是前面EmployeeInfo类的Name属性所转换的中间语言代码(不过省略了函数的具体实现代码,因为这里并不是为了研究中间语言代码,如果需要对这部分有更多地了解,参看中间语言相关书籍)。

  疑问二:就是用属性的效率是否仅次于第一种方法。

  从上面很容易看出,属性在编译的时候会转换成和成员函数一样的代码,那么它的效率应该和成员函数是一样的。其实并不是这样,因为JIT编译器会把属性所转换成的两个成员函数作为内联函数,这样效率会提高很多。(注:内联函数是代码被插入到调用者代码处的函数,通过避免函数调用所产生的额外开销,从而提高执行效率。不过书中也提到,即使不是内联函数,成员函数相对于方法一的效率损失也是微乎其微的。)

  用C#写程序,一提到属性,大家都会编写。其实在属性中,可以产生很多应用,接着来就分别说明。

  <!--[if !supportLists]-->1. <!--[endif]-->在属性中使用索引符,例如像“ArrayList[i]”来访问ArrayList某个成员。这里需要注意的是,属性名以及索引参数的编码格式是固定的,如“this […]”。不过索引参数可以是多个,而且不光支持整型参数,还可以使用其他类型参数。例如:


public ReturnValueType this[ ParType1 parValue1, ParType2 parValue2]
{
 get{...}
 set{...}
}

  <!--[if !supportLists]-->2. <!--[endif]-->可以给属性操作加上互斥锁,以防止多线程操作时而产生的并发错误,具体如下。


public string Name
{
 get
 {
  lock(this)
  {
   return strName;
  }
 }
 set
 {
  lock(this)
  {
   strName = value;
  }
 }
}

  <!--[if !supportLists]-->3. <!--[endif]-->书上还提到属性的其他应用,例如:通过接口来实现在一个类中同时提供只读属性以及非只读属性。但是我个人认为,虽然这样可以实现,但是会产生歧义,即在一个类中提供两个不同版本的属性,破坏了类的一致性,所以我并不推荐这么做。

  接着,要说说编写属性的时候,需要注意些什么,我个人认为有如下两点大的方面。

  第一个就是编写属性get部分的时候,如果当前属性的类型是引用类型的话,且不想通过属性来修改局部成员的话,最好返回局部成员的copy,而不是成员本身。

  例如:


public class class1
{
 string _data;
 public class1( string data )
 {
  _data = data;
 }

 public string Data
 {
  get{ return _data;}
  set{ _data = value;}
 }
}

public class class2
{
 private class1 myClass1 = null;
 public class1 Class1
 {
  get{ return myClass1; }
 }

 public string Data
 {
  get{ return myClass1.Data;}
 }

 public class2( string data )
 {
  myClass1 = new class1( data );
 }
}

  如果按照如上所写,那么class2对象可以通过Class1.Data属性访问和修改局部成员myClass1某些值,这样就可以修改了myClass2的私有成员myClass1的值,即会产生潜在错误。

  例如:


class1 myClass1 = myClass2.Class1;
myClass1.Data = "test2";

  如何避免这类错误呢,那么首先需要修改Class1属性的编写,其次在class1类需要提供Clone函数或者其他copy函数,具体如下:


public class class1:ICloneable
{
 string _data;
 public class1( string data )
 {
  _data = data;
 }

 public string Data
 {
  get{ return _data;}
  set{ _data = value;}
 }

 #region ICloneable Members

 public object Clone()
 {
  // TOD Add class1.Clone implementation
  return new class1( _data );
 }
 #endregion
}

public class class2
{
 private class1 myClass1 = null;
 public class1 Class1
 {
  get{ return myClass1.Clone() as class1; }
 }

 public string Data
 {
  get{ return myClass1.Data;}
 }

 public class2( string data )
 {
  myClass1 = new class1( data );
 }
}


  第二个需要注意的是编写属性set部分的时候,这里需要对参数进行有效性检查。因为属性是外界修改类的私有成员的入口,为了避免因为私有成员不正确而产生的错误,所以在进行属性set的时候要进行有效性检查,从而保证私有成员对于整个类来说是有效的。

  那么在实际应用当中,与属性密切相关的就是实现两个窗体之间数据访问,这可能是写WinForm程序最基本的。不过很遗憾的是,网上在回答此类问题的时候,很多人都建议用第一种方法来解决。


来源:网络







添加到del.icio.us 添加到新浪ViVi 添加到百度搜藏 添加到POCO网摘 添加到天天网摘365Key 添加到和讯网摘 添加到天极网摘 添加到黑米书签 添加到QQ书签 添加到雅虎收藏 添加到奇客发现 diigo it 添加到饭否 添加到飞豆订阅 添加到抓虾收藏 添加到鲜果订阅 digg it 貼到funP 添加到有道阅读 Live Favorites 添加到Newsvine 打印本页 用Email发送本页 在Facebook上分享


Disclaimer Privacy Policy About us Site Map

If you have any requirements, please contact webmaster。(如果有什么要求,请联系站长)
Copyright ©2011-
uuhomepage.com, Inc. All rights reserved.