彩票走势图

【More Effective C#】Partial Class是怎样炼成的?

转帖|其它|编辑:郝浩|2010-10-28 14:34:41.000|阅读 745 次

概述:C#中.我们可以利用部分类,将一个类分散到多个类文件中,这样我们就可以多个开发者同时开发某个类库,或者是扩展其他开发者发布的类库.甚至是代码生成器生成的代码,例如LINQ2SQL,ADO.NET EF等,以获取更高效的开发.

# 慧都年终大促·界面/图表报表/文档/IDE等千款热门软控件火热促销中 >>

什么是部分类(Partial Class)?

  C#中.我们可以利用部分类,将一个类分散到多个类文件中,这样我们就可以多个开发者同时开发某个类库,或者是扩展其他开发者发布的类库.甚至是代码生成器生成的代码,例如LINQ2SQL,ADO.NET EF等,以获取更高效的开发.

  Re:Class和Class File的区别.这里的类是我们平时所说的普通类-Class,如抽象类,基类,子类等等.而类文件-Class File则是我们平时编写类时所用到的文件,如C#的.cs,VB的.vb.

  虽然部分类很好的解决了多个开发者同时开发而互不影响的问题,但其约束十分严格.开发者之间不能/很难彼此沟通,并且无法/很难修改对方的代码.这意味着需要为对方提供很多挂钩.这些挂钩应该以部分方法的方式实现.而另一方的开发者可以选择实现或不实现.

扩展现有类

  实体框架的出现,大大的减轻了我们的工作量,使我们把更多的重心放在逻辑实现上,而减少对于数据访问的关注.例如我们可以使用LINQ2SQL,LINQ2SQL是一个轻型的实体框架.它生成了我们对数据层的访问.但.有些时候,我们需要扩展些自己的内容,如方法/属性等等.除了直接在生成的类文件中添加修改意外,我们还可以利用部分类扩展我们所需的功能,前者当每次我们跟新实体时.你所扩展的内容都会消失.而部分类依然能很好的为你服务.

提供部分方法

  为部分类提供最有效的钩子就是部分方法.它和接口的方法声明很相似.

  关键字partial+void+方法名+方法参数.

partial void ReportValueChanging(RequestChange args);

由于部分方法可能成为类的一部分(实现),也可能不成为类的一部分(不实现),所以C#本身对于部分方法给出了一些限制.

1.返回类型必须为void.

2.部分方法不能为抽象/虚方法.

3.部分方法不能用来实现接口.

4.参数列表不能包含任何out参数,因为编译器无法初始化这些out参数.

   我们利用部分方法来让用户件事或修改类的行为:修改方法,事件处理程序及构造函数.

修改方法

  修改方法是指那些将要修改类中对外可见的状态的方法.我们可以将其理解为任何状态的变化,由于另一个类文件的部分类实现依然是类的一部分.所以我们可以完全控制到该类的所有内部状态.

  一般而言,修改方法应该为类提供两个部分方法.第一个在修改前调用,用来让另一方(另一开发者)能够进行合法性验证等等.第二个方法应该在修改状态后调用,用来让另一方相应这个状态的变化.

public partial class GeneratedStuff  
    {     
     private struct ReportChange  
        {    
   public readonly int OldValue;  
            public readonly int NewValue;        
  public ReportChange(int oldValue, int newValue)   
           {        
 this.OldValue = oldValue;  
                this.NewValue = newValue;       
       }       
   }   
         private class RequestChange
          {          
    public ReportChange Values    
          {                
  get;         
         set;         
     }         
     public bool Cancel      
        {            
      get;           
       set;           
   }        
  }          
  partial void ReportValueChanging(RequestChange args);    
      partial void ReportValueChanged(ReportChange values);       
     private int storage = 0; 
           public void UpdateValue(int newValue)    
      {     
 RequestChange updateArgs = new RequestChange
              {         
 Values = new ReportChange(storage, newValue)
              };   
  ReportValueChanging(updateArgs);  
  if (!updateArgs.Cancel)  
            {    
     storage = newValue; 
  ReportValueChanged(new ReportChange(storage, newValue));     
         }  
        }  
    }

  如果另一个部分类没有提供两个部分方法的实现,那么C#编译器将移除该调用.生成方法如下

public void UpdateValue(int newValue)  
        {  
   RequestChange updateArgs = new RequestChange   
  {        
 Values = new ReportChange(this.storage, newValue)  
   };  
    if (!updateArgs.Cancel)
    {  
 this.storage = newValue; 
 }
 }

  并且,两个部分方法也一并移除了.

  我们可以实现挂钩如下

public partial class GeneratedStuff
 { 
partial void ReportValueChanging(GeneratedStuff.RequestChange args) 
 { 
 if (args.Values.NewValue < 0)  
{ 
  //dosomething...  
 } 
else  
 { 
 //dosomething... 
  }
  } 
 partial void ReportValueChanged(GeneratedStuff.ReportChange values) 
{  
 //dosomething...  
}  
 }

  这里,我们通过一个取消标记来让开发者可以取消某个修改动作,你也可以通过抛出异常得到同样的效果.但.推荐使用布尔型的取消标记,因为这样更加轻量一些

事件处理程序

  实际上,事件的处理程序和上面的方法修改并无多大的区别.你所需要做的.仅仅只是添加一个委托事件而已.实现了类似控件的事件机制.

构造函数扩展

  无论是生成的代码,还是我们手工编写的代码.我们都无法预计调用类时外部将会调用哪个构造函数.所以.我们只能在内部做一些手脚.例如

  public partial class GeneratedStuff

  {

   partial void Initialize();

   public GeneratedStuff() :

  this(0)

   { }

   public GeneratedStuff(int someValue)

  { this.storage = someValue; Initialize();

   }

   }

  注意!Initialize在最后调用,这样就有了一次检查当前对象状态的机会,可以进行必要的修改,或是对于不符合要求时抛出异常等等.实际上.这种构造函数重载也有效的提升你的代码质量(对于不同的构造函数,结果IL都会生成不同的函数块.而这种重构法最后其实真正生成的函数块只有一个)

尾声

  经过以上的阐述,相信我们已经更了解部分类是怎样炼成的了.只有更好的了解其背后的一系列"小动作",才有助于我们更好的提升,写出更有质量的代码


标签:

本站文章除注明转载外,均为本站原创或翻译。欢迎任何形式的转载,但请务必注明出处、不得修改原文相关链接,如果存在内容上的异议请邮件反馈至chenjj@pclwef.cn

文章转载自:网络转载

为你推荐

  • 推荐视频
  • 推荐活动
  • 推荐产品
  • 推荐文章
  • 慧都慧问
扫码咨询


添加微信 立即咨询

电话咨询

客服热线
023-68661681

TOP