地址:http://www.codeproject.com/KB/viewstate/ViewStateAttribute.aspx
背景
当我们在页面中创建一个ViewState,我们通常为ViewState创建一个属性,像这样:
private
int
ViewState_UserID
{
get
{
return
(
int
) ViewState[
"
UserId
"
]; }
set
{ ViewState[
"
UserId
"
]
=
value; }
}
你不觉得创建2个访问器有点令人讨厌吗? 能够使这个简单一些像一个自动的属性吗?像这样:
[ViewStateProperty(
"
UserID
"
)]
protected
int
ViewState_UserID {
get
;
set
;}
或者
[ViewStateProperty]
protected
int
ViewState_UserID {
get
;
set
;}
代码详情
第一步:让我们创建一个从System.Web.UI.Page继承的BasePage,为一个更高层次的应用创建BasePage很普遍。我们将在这里使用反射和Linq。
using
System.Reflection;
using
System.Linq;
public
class
BasePage : System.Web.UI.Page
第二步:在BasePage里创建一个继承自Attribute的内部类ViewStateProperty,Attribute类的目的是为了描述页面中的属性是viewstate属性。理论上,attribute的目标是viewstate属性,因此它应该在页面里。
代码
[AttributeUsage(AttributeTargets.Property)]
public
class
ViewStateProperty : Attribute
{
public
string
ViewStateName {
get
;
private
set
; }
internal
ViewStateProperty(){
this
.ViewStateName
=
string
.Empty;
}
public
ViewStateProperty(
string
in_ViewStateName){
this
.ViewStateName
=
in_ViewStateName;
}
}
[AttributeUsage(AttributeTargets.Property)]意味着该attribute仅用于属性类型。public ViewStateProperty(string in_ViewStateName)构造器的目的是为了初始化ViewState名字。默认地,ViewState的名字为空。当设置attribute的时候,如果你想初始化ViewState名字,请使默认构造器为private。
第三步:在BasePage里,创建一个ViewStateProperties变量,存储那些有ViewStateProperty特征的属性,同时在BasePage里面的默认构造器初始化它们。
代码
private
PropertyInfo[] ViewStateProperties;
protected
BasePage()
{
this
.ViewStateProperties
=
GetType().GetProperties(
BindingFlags.NonPublic
|
BindingFlags.Instance).Where(
p
=>
p.GetCustomAttributes(
typeof
(ViewStateProperty),
true
).Length
>
0
).ToArray();
}
GetType().GetProperties(BindingFlags.NonPublic | BindingFlags.Instance)的作用是在页面里通过反射获得所有public和protected的属性。Where(p => p.GetCustomAttributes(typeof(ViewStateProperty), true).Length > 0)的作用是过滤那些被ViewStateProperty特征(attribute)修饰的属性.
第四步:在BasePage里面覆盖(override)LoadViewState和SaveViewState方法
代码
protected
override
void
LoadViewState(
object
savedState)
{
base
.LoadViewState(savedState);
foreach
(PropertyInfo property
in
ViewStateProperties)
{
ViewStateProperty[] attributes
=
(ViewStateProperty[])
property.GetCustomAttributes(
typeof
(ViewStateProperty),
false
);
var LocalName
=
(
string
.Empty
==
attributes[
0
].ViewStateName)
?
property.Name : attributes[
0
].ViewStateName;
if
(ViewState[LocalName]
!=
null
)
property.SetValue(
this
, ViewState[LocalName],
null
);
}
}
protected
override
object
SaveViewState()
{
foreach
(PropertyInfo property
in
ViewStateProperties)
{
ViewStateProperty[] attributes
=
(ViewStateProperty[])
property.GetCustomAttributes(
typeof
(ViewStateProperty),
false
);
var LocalName
=
(
string
.Empty
==
attributes[
0
].ViewStateName)
?
property.Name:attributes[
0
].ViewStateName;
ViewState[LocalName]
=
property.GetValue(
this
,
null
);
}
return
base
.SaveViewState();
}
我们的目标是建立在名称上,我们确定了ViewStateProperty特征或本身
由ViewStateProperty特征修饰的属性名称;加载ViewState的值到被ViewStateProperty特征修饰的属性上。
使用
在开始谈到的,很容易实现
[ViewStateProperty(
"
UserID
"
)]
protected
int
ViewState_UserID {
get
;
set
;}
或者
ViewStateProperty]
protected
int
ViewState_UserID {
get
;
set
;}
第一个,设置一个称作UserID的ViewState,第二个,设置一个称作ViewState_UserID的ViewState。
注释
实现这样的属性,你不能设置它们为private,因为GetType().GetProperties(BindingFlags.NonPublic | BindingFlags.Instance)不会返回private属性,但是protected能够做到我们的目标。