最近买了本 C#2005 Business Objects 基于一个CSLA.NET开源项目展开的。大致看了下,觉得比较深奥。需要结合CSLA源码。不过在深入源码之前我决定先复习一个BlogEngine.Net。BlogEngine得核心类可以理解为是CSLA的阉割版。
BusinessBase 是BlogEngine所有业务的基类。
1.首先我们看下它继承了那些接口
public abstract class BusinessBase<TYPE, KEY> : IDataErrorInfo, INotifyPropertyChanged, IChangeTracking, IDisposable where TYPE : BusinessBase<TYPE, KEY>, new()
1.1 IDataErrorInfo
该功能提供用户界面可以绑定的自定义错误信息。
public string Error
{
get { return ValidationMessage; }
}
public string this[string columnName]
{
get
{
if (_BrokenRules.ContainsKey(columnName))
return _BrokenRules[columnName];
return string.Empty;
}
}
这个接口虽然被实现。我发现没有使用,不清楚作者如何处理了。
1.2 INotifyPropertyChanged
向客户端发出某一属性值已更改的通知。
/// <summary>
/// Occurs when this instance is marked dirty.
/// It means the instance has been changed but not saved.
/// </summary>
public event PropertyChangedEventHandler PropertyChanged;
MSDN: ms-help://MS.MSDNQTR.v90.chs/fxref_system/html/d7424bfd-9de2-e553-d64e-57a78a2134d4.htm
INotifyPropertyChanged 接口用于向客户端(通常是执行绑定的客户端)发出某一属性值已更改的通知。
例如,考虑一个带有名为 FirstName 属性的 Person 对象。若要提供一般性属性更改通知,则 Person 类型实现 INotifyPropertyChanged 接口并在 FirstName 更改时引发 PropertyChanged 事件。如果数据源实现 INotifyPropertyChanged 并且您执行的是异步操作,则不得在后台线程上对数据源进行更改。相反,应在后台线程上读取这些数据并将这些数据合并到 UI 线程上的列表中。
若要在将客户端与数据源进行绑定时发出更改通知,则绑定类型应具有下列任一功能:
-
实现 INotifyPropertyChanged 接口(首选)。
-
为绑定类型的每个属性提供更改事件。
1.3 IChangeTracking
定义查询对象更改以及重置更改后的状态的机制。
/// <summary>
/// Resets the object state to unchanged by accepting the modifications.
/// </summary>
void IChangeTracking.AcceptChanges()
{
Save();
}
1.4 IDisposable
这个大家都很熟悉了
private bool _IsDisposed;
protected bool IsDisposed
{
get { return _IsDisposed; }
}
protected virtual void Dispose(bool disposing)
{
if (this.IsDisposed)
return;
if (disposing)
{
_ChangedProperties.Clear();
_BrokenRules.Clear();
_IsDisposed = true;
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
1.5 where TYPE : BusinessBase<TYPE, KEY>, new()
所有业务类都必须继承这个BusinessBase,否则vs就会送你个error。
2.BusinessBase具有那些功能
2.1 获取对象的状态
2.1.1 IsNew
private bool _IsNew = true;
初始化=true
True: 说明这个对象是新创建的
False:说明已经存在这个对象了
2.1.2 IsDeleted,IsChanged
也是用来做判断标记
2.2 Validation 规则
IsValid 标记 是否需要验证。
ValidationRules()方法为虚方法。也是在继承类中实现,看下BlogRollItem.cs代码
AddRule()方法中最后一个参数确定了是否应用这些规则。
2
3 /// < summary >
4 /// Add or remove a broken rule.
5 /// < /summary >
6 /// < param name = " propertyName " > The name of the property. < /param >
7 /// < param name = " errorMessage " > The description of the error < /param >
8 /// < param name = " isBroken " > True if the validation rule is broken. < /param >
9 protected virtual void AddRule ( string propertyName, string errorMessage, bool isBroken )
10 {
11 if ( isBroken )
12 {
13 _BrokenRules [ propertyName ] = errorMessage;
14 }
15 else
16 {
17 if ( _BrokenRules . ContainsKey ( propertyName ) )
18 {
19 _BrokenRules . Remove ( propertyName ) ;
20 }
21 }
22 }
23
24 protected abstract void ValidationRules ( ) ;
25
26 public bool IsValid
27 {
28 get
29 {
30 ValidationRules ( ) ;
31 return this . _BrokenRules . Count = = 0 ;
32 }
33 }
BlogRollItem.cs
2 {
3 AddRule ( " Title " , " Title must be set " , string . IsNullOrEmpty ( Title ) ) ;
4 AddRule ( " BlogUrl " , " BlogUrl must be set " , BlogUrl = = null ) ;
5 }
最后在提交按钮之前做了处理 ,代码截取了片段
ValidationMessage 是将错误信息写成字符串的一个方法
BusinessBase .cs
2 {
3
4 if ( IsDeleted && ! ( IsAuthenticated | | isValidated ) )
5 throw new System . Security . SecurityException ( " You are not authorized to delete the object " ) ;
6
7 if ( ! IsValid && ! IsDeleted )
8 throw new InvalidOperationException ( ValidationMessage ) ;
9
10 return SaveAction . None;
11 }
2.3 通用数据访问
运用了模板模式,在其继承类实现DataSelect方法。调用其继承类的A类的方法只需XXX.Load(id).
而无需在A类设定对象的状态,体现了代码的高度重用。
代码如下:
1 /// <summary>
2 /// Loads an instance of the object based on the Id.
3 /// </summary>
4 /// <param name="id">The unique identifier of the object</param>
5 public static TYPE Load(KEY id)
6 {
7 TYPE instance = new TYPE();
8 instance = instance.DataSelect(id);
9 instance.Id = id;
10
11 if (instance != null)
12 {
13 instance.MarkOld();
14 return instance;
15 }
16
17 return null;
18 }
19
20 /// <summary>
21 /// Retrieves the object from the data store and populates it.
22 /// </summary>
23 /// <param name="id">The unique identifier of the object.</param>
24 /// <returns>True if the object exists and is being populated successfully</returns>
25 protected abstract TYPE DataSelect(KEY id);
再看一个方法:
2 /// Saves the object to the data store (inserts, updates or deletes).
3 /// < /summary >
4 public virtual SaveAction Save ( string userName, string password )
5 {
6 bool isValidated;
7 if ( userName = = string . Empty )
8 isValidated = false ;
9 else
10 isValidated = Membership . ValidateUser ( userName, password ) ;
11
12 if ( IsDeleted && ! ( IsAuthenticated | | isValidated ) )
13 throw new System . Security . SecurityException ( " You are not authorized to delete the object " ) ;
14
15 if ( ! IsValid && ! IsDeleted )
16 throw new InvalidOperationException ( ValidationMessage ) ;
17
18 if ( IsDisposed && ! IsDeleted )
19 throw new InvalidOperationException ( string . Format ( CultureInfo . InvariantCulture, " You cannot save a disposed {0} " , this . GetType ( ) . Name ) ) ;
20
21 if ( IsChanged )
22 {
23 return Update ( ) ;
24 }
25
26 return SaveAction . None;
27 }
也是运用了模板模式,和上一段代码的区别在于使用了虚方法。
总结:BlogEngine.Net是个非常好的学习源码。