使用 ViewState 属性自动生成 ViewState 属性
自动 ViewState 属性。
引言
本文将演示如何通过属性实现自动 ViewState 属性。
背景
当我们在页面中创建一个 ViewState
时,我们通常会为这个 ViewState
创建一个属性。 像这样:
private int ViewState_UserID
{
get { return (int) ViewState["UserId"]; }
set { ViewState["UserId"] = value; }
}
当您尝试创建几个时,您是否觉得有点无聊? 是否可以像自动属性一样简单? 像这样:
[ViewStateProperty("UserID")]
protected int ViewState_UserID { get; set;}
或
[ViewStateProperty]
protected int ViewState_UserID { get; set;}
是的,有一种简单的方法可以使用 Attribute
来实现它。
代码详情
第一步,让我们创建一个继承自 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 属性。 从理论上讲,此属性针对 viewstate 属性,因此它应该位于 BasePage
内部。
[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)]
表示此属性仅适用于属性类型。 public ViewStateProperty(string in_ViewStateName)
构造函数用于初始化 ViewState 名称。 默认情况下,ViewState 名称为空。 如果您想在设置属性时初始化 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
属性修饰的属性。
第四步是覆盖 BasePage
中的 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; 并将 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
对于我们的目标来说已经足够了。