利用反射解决QueryString和Session中的参数绑定问题

注:去年写的一篇文章了,现在把它贴出来,以做参考
这里是 示例代码
利用反射解决
QueryString Session 中的参数绑定问题

一.     前言

本文主要译自网上的一篇文章(http://www.codeproject.com/aspnet/WebParameter.asp),自己又作了一些改进,因此形成了这篇心得。

 

二.     简介:

本文介绍了在ASP.NET页面对象中利用元数据自动从Page.Request对象的QueryString中填充页面的变量和属性的策略.

 

三.     问题的提出

当你对ASP.NET页面进行参数化时,比如:从Request.QueryStringGET)或Request.FormPOST)中获取参数,你需要花大量的时间写类似以下的代码:

None.gif protected   string  FirstName
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif    
get
ExpandedSubBlockStart.gif 
dot.gif{
InBlock.gif     
return Request.QueryString["FirstName"]; 
ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}

None.gif

 


但是你必须处理潜在的
FirstNamenull值是的情况,因此你可能会通过如下的代码提供一个缺省值

ExpandedBlockStart.gif ContractedBlock.gif protected   static   string  IsNull( string  test,  string  defaultValue) dot.gif {
InBlock.gif    
return test==null ? defaultValue : test;
ExpandedBlockEnd.gif}

None.gif
ExpandedBlockStart.gifContractedBlock.gif
protected   string  FirstName_NullSafe dot.gif {
ExpandedSubBlockStart.gifContractedSubBlock.gif   
getdot.gifreturn IsNull(Request.QueryString["FirstName"],""); }
ExpandedBlockEnd.gif}

None.gif

对于非字符串类型,你也可以通过稍微修改以上代码来决定当参数为null时是提供一个缺省值还是抛出一个异常,只是要用到Convert.ToXXX()函数

ExpandedBlockStart.gif ContractedBlock.gif protected   int  CustomerID dot.gif {
ExpandedSubBlockStart.gifContractedSubBlock.gif    
getdot.gif
          {
InBlock.gif               
object o=Request.QueryString["CustomerID"];
InBlock.gif               
if (o==null)//如果为空,则抛出异常
InBlock.gif
                {
                       
throw new  ApplicationException("Customer ID is required to be passed"); 
                   }
InBlock.gif               
else
                   {
 
ExpandedSubBlockStart.gifContractedSubBlock.gif                   
trydot.gif
                          {
                                //如果不空,转换成Int32型
InBlock.gif
                            return Convert.ToInt32(o,10);
ExpandedSubBlockStart.gifContractedSubBlock.gif                    }
                         catch(Exception err)dot.gif
                         {
InBlock.gif                           
throw new ApplicationException("Invalid CustomerID", err);
ExpandedSubBlockEnd.gif                      }

ExpandedSubBlockEnd.gif                }

ExpandedBlockEnd.gif       }

None.gif}
None.gif

 

因此,在Page_Load函数里你可能会写如下的代码进行参数初始化

ExpandedBlockStart.gif ContractedBlock.gif private   void  Page_Load( object  sender, System.EventArgs e)  dot.gif
   {
InBlock.gif       
string o;
InBlock.gif
InBlock.gif       
// 提供一个初始值
InBlock.gif
        FirstName2 =IsNull(Request.QueryString["FirstName"], "");
InBlock.gif
InBlock.gif       
//确保该值不为空,否则抛出异常
InBlock.gif
        o =Request.QueryString["CustomerID"];
InBlock.gif       
if (o==null)
InBlock.gif           
throw new  ApplicationException("Customer ID is required to be passed");
InBlock.gif       
else
ExpandedSubBlockStart.gifContractedSubBlock.gif          
trydot.gif{//如果转换类型不正常,抛出异常
InBlock.gif
                CustomerID2 = Convert.ToInt32(o,10);
ExpandedSubBlockStart.gifContractedSubBlock.gif          }
             
catch(Exception err)dot.gif{
InBlock.gif               
throw new ApplicationException("Invalid CustomerID", err);
ExpandedSubBlockEnd.gif           }

InBlock.gif
ExpandedBlockEnd.gif }

None.gif

小结:

当你在处理从Request.QueryStringRequest.Form读取参数时,有以下的固定模式

  • Request.QueryString ( Request.Form)中检索值,

  • 当检索的值为空时抛出异常或提供一个缺省值

  • 将检索到的值转换成合适的数据成员(field)或属性(property

  • 如果检索值不能正确转换类型,抛出一个异常或提供一个缺省值

四.     解决方案:声明性参数绑定

l         表现形式:

一个解决的方案是使用元数据(metadata),并让一些函数执行实际的工作

比如说以下形式:

None.gif  [WebParameter()]
None.gif
protected   string  FirstName;
None.gif
// 如果没有提供参数,则表示查找和FirstName同名的关键字,
None.gif
// 即QueryString[“FirstName”],
None.gif

None.gif[WebParameter(
" Last_Name " )]
None.gif
protected   string  LastName;
None.gif
// 表示从QueryString中查找"Last_Name"的变量值
None.gif
// 即QueryString[“Last_Name”]
None.gif

None.gif[WebParameter(IsRequired
= true )]
None.gif
protected   int  CustomerID;
None.gif
// 表示如果QueryString[“CustomerID”]返回空值,则抛出异常
None.gif

可选的构造函数提供了从Request.QueryString中查找参数的关键字,IsRequired属性决定了当该参数缺失时是否抛出异常。  

 

l         思路

本解决方案的思路是,利用反射来检索到附加在变量上的元数据,然后根据该元数据的属性决定如何对变量进行存取,其存取模式采用如第2节(《问题的提出》)最后一部分小结里的模式,只是改成了由程序自动判断进行。

1、  检索元数据属性

如前所述,当先定义一个从System.Attribute派生的元数据类WebParameterAttribut


None.gif [AttributeUsage(AttributeTargets.Field  |  AttributeTargets.Property, AllowMultiple = false , Inherited = true )]
None.gif
public   class  WebParameterAttribute : Attribute
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif        
public int ParamName;
InBlock.gif
InBlock.gif        
public string DefaultValue
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif            
getdot.gif{    return _default    ;   }
ExpandedSubBlockStart.gifContractedSubBlock.gif            
setdot.gif{    _default=value    ;    }
ExpandedSubBlockEnd.gif     }

ExpandedBlockEnd.gif}

None.gif

 

注:AttributeUsageAttribute使用说明

 

说明:



None.gif [WebParameter( " Last_Name " )]
None.gif
protected   string  LastName;
None.gif


    当以上面形式使用自定义的属性类时,实际上等与是生成了一个和LastName的类型对象LastName.GetType()相关联的WebParameterAttribute类的对象,通过LastName.GetType()对象可以检索到WebParameter对象的一些方法成员、数据成员以及属性等;

我们可以定义WebParameterAttribute类的静态方法,WebParameterAttribute.SetValues(object target, System.Web.HttpRequest request)完成自动初始化某个页面的所有参数,该方法有两个参数target表示将被自动进行参数化的对象例如可以是某个页面对象Page);request是在某个页面对象的初始化时传来的Request对象;后面我们会详细解释SetValues方法的设计


示例如下面粗体部分所示:


None.gif public   class  WebParameterDemo : System.Web.UI.Page
ExpandedBlockStart.gifContractedBlock.gif    
dot.gif {
InBlock.gif        [WebParameter(
"txtFirstName")]
InBlock.gif        
public string FirstName        ="field default";
InBlock.gif
InBlock.gif        [WebParameter(
"txtLastName", DefaultValue="attribute default")]
ExpandedSubBlockStart.gifContractedSubBlock.gif        
public string LastNamedot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif            
getdot.gif{    return (string)ViewState["LastName"];    }
ExpandedSubBlockStart.gifContractedSubBlock.gif            
setdot.gif{    ViewState["LastName"]=value;            }
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        [WebParameter (
"txtCustomerID", DefaultValue="0")]
InBlock.gif        
public int CustomerID;
InBlock.gif
InBlock.gif        
int TestNum;//注意该数据成员没有关联WebParameter属性
InBlock.gif

InBlock.gif        
protected System.Web.UI.HtmlControls.HtmlInputText txtFirstName;
InBlock.gif        
protected System.Web.UI.HtmlControls.HtmlInputText txtLastName;
InBlock.gif        
protected System.Web.UI.HtmlControls.HtmlInputText txtCustomerID;
InBlock.gif
InBlock.gif        
private void Page_Load(object sender, System.EventArgs e)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            WebParameterAttribute.SetValues(
this, Request);
InBlock.gif           
//注意这里是用法
InBlock.gif
            txtFirstName.Value    =FirstName;
InBlock.gif            txtLastName.Value    
=LastName;
InBlock.gif            txtCustomerID.Value    
=CustomerID.ToString();
ExpandedSubBlockEnd.gif        }

InBlock.gif    
InBlock.gif



    在上面的示例中,静态方法WebParameterAttribut.SetValues先获取this指针代表的Page对象的类型对象this.GetType(),然后用该类型对象获取Page对象的所有变量和属性的信息,即可以获得并操纵Page对象的FirstNameLastNameCustomerID,也包括TestNum。然后SetValues方法检查每个检索到的变量和属性,看有没有关联WebParameter对象,相对来说,数据成员TestNum就没有关联WebParameter对象。

SetValues检测到变量(field)或属性(property)关联有WebParameter对象时,该方法会检索和变量或属性向关联的WebParameter对象的具体属性,比如说:



None.gif [WebParameter( " Last_Name " )]
None.gif
protected   string  LastName;
None.gif


生成了一个WebParameter对象,并传递给构造函数一个参数”Last_Name”SetValues方法会检测出和string LastName相关联的WebParameter中包含的“Last_Name”并将其作为要在QueryString中检测的变量的名字。

 

 

 

 

l         代码解析

下面是SetValues的具体实现:

 

²        变量及属性定义


None.gif     [AttributeUsage(AttributeTargets.Field  |  AttributeTargets.Property, AllowMultiple = false , Inherited = true )]
None.gif    
public   class  WebParameterAttribute : Attribute
ExpandedBlockStart.gifContractedBlock.gif    
dot.gif {
ContractedSubBlock.gifExpandedSubBlockStart.gif        
定义私有变量#region 定义私有变量
InBlock.gif               
string _default;    //缺省值
InBlock.gif
                string _name;    //要从QueryString中检测的变量的名称
InBlock.gif
                bool _isRequired;    //是否为必须值,如果缺失则抛出异常
InBlock.gif               
//如果传递的参数类型转换失败,是否设缺省值
InBlock.gif
                bool _isDefaultForInvalid;    
InBlock.gif
ExpandedSubBlockEnd.gif           
#endregion

InBlock.gif
ContractedSubBlock.gifExpandedSubBlockStart.gif        
Constructors#region Constructors
InBlock.gif               
//构造函数,传递paraName,以便用QueryString[paraName]检索
InBlock.gif
                public WebParameterAttribute(string paramName)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif                    _name        
=paramName;
ExpandedSubBlockEnd.gif               }

ExpandedSubBlockEnd.gif        
#endregion

InBlock.gif        
InBlock.gif
InBlock.gif        
public string ParameterName
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif            
getdot.gif{    return _name;    }
ExpandedSubBlockStart.gifContractedSubBlock.gif            
setdot.gif{    _name=value;    }
ExpandedSubBlockEnd.gif            }

InBlock.gif    
InBlock.gif        
public string DefaultValue
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif            
getdot.gif{    return _default    ;    }
ExpandedSubBlockStart.gifContractedSubBlock.gif            
setdot.gif{    _default=value    ;    }
ExpandedSubBlockEnd.gif            }

InBlock.gif    
InBlock.gif        
public bool IsRequired
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif            
getdot.gif{    return _isRequired;    }
ExpandedSubBlockStart.gifContractedSubBlock.gif            
setdot.gif{    _isRequired=value;    }
ExpandedSubBlockEnd.gif           }

InBlock.gif    
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// </summary>
InBlock.gif        public bool IsDefaultUsedForInvalid
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif            
getdot.gif{    return _isDefaultForInvalid;    }
ExpandedSubBlockStart.gifContractedSubBlock.gif            
setdot.gif{    _isDefaultForInvalid=value;    }
ExpandedSubBlockEnd.gif        }

InBlock.gif


 

 

²        SetValues方法

request中检索特定值并设定target中指定变量和属性的值

None.gif public   static   void  SetValues( object  target, System.Web.HttpRequest request) 
None.gif
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {//传入的target对象可以是Page对象,request可以是Page.Request对象 
InBlock.gif
InBlock.gif       
//获取target的类型信息 
InBlock.gif

InBlock.gif         System.Type type    
=target.GetType(); 
InBlock.gif
InBlock.gif  
InBlock.gif
InBlock.gif         
InBlock.gif
InBlock.gif         
//获取target公开的、实例化后的成员信息 
InBlock.gif

InBlock.gif         MemberInfo[] members
= type.GetMembers(BindingFlags.Instance | 
InBlock.gif
InBlock.gif         BindingFlags.Public
| 
InBlock.gif
InBlock.gif        BindingFlags.NonPublic); 
InBlock.gif
InBlock.gif       
//Instance:只对非静态的成员查找; 
InBlock.gif
InBlock.gif       
//Public:只对具有公开访问属性的成员进行查找 
InBlock.gif
InBlock.gif       
//在和Instance或static联用时, 
InBlock.gif
InBlock.gif       
//必须指定NonPublic或Public,否则返回空值 
InBlock.gif

InBlock.gif  
InBlock.gif
InBlock.gif         
foreach(MemberInfo member in members) 
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif      
dot.gif
InBlock.gif
InBlock.gif             
if((member is FieldInfo) || (member is PropertyInfo)) 
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif          
dot.gif{//对变量和属性,设置其初始值 
InBlock.gif

InBlock.gif                     SetValue(member, target, request); 
InBlock.gif
ExpandedSubBlockEnd.gif             }
 
InBlock.gif
ExpandedSubBlockEnd.gif         }
 
InBlock.gif
ExpandedBlockEnd.gif}
 
None.gif
None.gif

 

 

²        SetValue方法

根据member对象的类型是变量(Field)或属性(Property),从request中检索特定值并设置target.member的值

None.gif public   static   void  SetValue(MemberInfo member,  object  target, System.Web.HttpRequest request) 
None.gif
ExpandedBlockStart.gifContractedBlock.gif
dot.gif
InBlock.gif
InBlock.gif         WebParameterAttribute[] attribs; 
InBlock.gif
InBlock.gif         WebParameterAttribute attrib; 
InBlock.gif
InBlock.gif         TypeConverter converter; 
InBlock.gif
InBlock.gif         
string paramValue; 
InBlock.gif
InBlock.gif         
string paramName; 
InBlock.gif
InBlock.gif         
object typedValue; 
InBlock.gif
InBlock.gif         
bool usingDefault; 
InBlock.gif
InBlock.gif  
InBlock.gif
InBlock.gif         
try 
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif         
dot.gif
InBlock.gif
InBlock.gif                 attribs
=(WebParameterAttribute[])member.GetCustomAttributes(typeof(WebParameterAttribute), true); 
InBlock.gif
InBlock.gif                 
//返回和变量或属性关联的WebAttribute对象或其子类的对象 
InBlock.gif

InBlock.gif  
InBlock.gif
InBlock.gif                
if(attribs!=null && attribs.Length>0
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif              
dot.gif
InBlock.gif
InBlock.gif                        
//对于索引属性,不支持,所谓索引属性, 
InBlock.gif
InBlock.gif                        
//是指C#中可以用类似数组下标形式访问的属性 
InBlock.gif

InBlock.gif                         
if (member.MemberType==MemberTypes.Property) 
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif                      
dot.gif
InBlock.gif
InBlock.gif                             ParameterInfo[] ps
=  ((PropertyInfo)member).GetIndexParameters(); 
InBlock.gif
InBlock.gif                             
if (ps!=null && ps.Length>0
InBlock.gif
InBlock.gif                                   
throw new NotSupportedException("Cannot apply WebParameterAttribute to indexed property");  InBlock.gif
InBlock.gif

ExpandedSubBlockEnd.gif                 }
 
InBlock.gif
InBlock.gif  
InBlock.gif
InBlock.gif                 
//因为WebAttribute在每个成员上只能应用一次, 
InBlock.gif
InBlock.gif               
//所以取第一个就行了 
InBlock.gif

InBlock.gif                attrib
=attribs[0]; 
InBlock.gif
InBlock.gif                 
//获取[WebParameter(“Last_Name”)]中的”Last_Name”字符串 
InBlock.gif
InBlock.gif                 
//如果是类似[WebParameter()] string Name;形式,则 
InBlock.gif
InBlock.gif                 
//得到的名字是”Name”,和变量或属性的名字同名 
InBlock.gif

InBlock.gif                paramName
=(attrib.ParameterName!=null)? attrib.ParameterName : member.Name; 
InBlock.gif
InBlock.gif                 
InBlock.gif
InBlock.gif                 
//下面将获取paramValue值,但是是string类型 
InBlock.gif
InBlock.gif                 
//WebParameter自定义方法GetValue,后面有说明 
InBlock.gif
InBlock.gif               
//从request对象获取QueryString[paramName]值 
InBlock.gif
InBlock.gif               
//或是Form[paramName]值 
InBlock.gif

InBlock.gif                 paramValue
=attrib.GetValue(paramName, request); 
InBlock.gif
InBlock.gif  
InBlock.gif
InBlock.gif                 
//如果在QueryString中未检索到paramName所对应的值 
InBlock.gif

InBlock.gif                 usingDefault    
=false
InBlock.gif
InBlock.gif                
if (paramValue==null
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif             
dot.gif
InBlock.gif
InBlock.gif                     
if (attrib.DefaultValue!=null
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif                  
dot.gif{//如果设定了缺省值,则用缺省值定赋值 
InBlock.gif

InBlock.gif                         paramValue  
=attrib.DefaultValue; 
InBlock.gif
InBlock.gif                         usingDefault    
=true
InBlock.gif
ExpandedSubBlockEnd.gif                     }
 
InBlock.gif
InBlock.gif                     
else if (!attrib.IsRequired) 
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif                  
dot.gif{//如果没有定义缺省值,且不要求一定有值,返回 
InBlock.gif

InBlock.gif                         
return// 仅仅跳过该值 
InBlock.gif

ExpandedSubBlockEnd.gif                     }
 
InBlock.gif
InBlock.gif                     
else 
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif                   
dot.gif{//如果要求必须有值,且未检索到值,则抛出异常 
InBlock.gif

InBlock.gif                         
throw new ApplicationException( 
InBlock.gif
InBlock.gif                                    String.Format( 
InBlock.gif
InBlock.gif                                           
"Missing required parameter '{0}'"
InBlock.gif
InBlock.gif                                            paramName) 
InBlock.gif
InBlock.gif                          ); 
InBlock.gif
ExpandedSubBlockEnd.gif                 }
 
InBlock.gif
InBlock.gif  
InBlock.gif
InBlock.gif                 
//下面将string类型的paramValue 
InBlock.gif
InBlock.gif               
//根据变量或属性的类型作转换,存放在typedValue中 
InBlock.gif
InBlock.gif                 
//对变量或属性,类型转换稍有不同 
InBlock.gif
InBlock.gif  
InBlock.gif
InBlock.gif                 
InBlock.gif
InBlock.gif                
//根据成员是变量(FieldType),属性(PropertyType) 
InBlock.gif
InBlock.gif               
//两种情况获取member的Type类型对象, 
InBlock.gif
InBlock.gif               
//如果不是变量或属性,则抛出异常 
InBlock.gif
InBlock.gif               
//注意:FiledInfo和PropertyInfo,MethodInfo 
InBlock.gif
InBlock.gif               
//都是MemberInfo的子类 
InBlock.gif
InBlock.gif               
//获取成员对应的类型转换器 
InBlock.gif

InBlock.gif                converter
=TypeDescriptor.GetConverter( 
InBlock.gif
InBlock.gif                            GetMemberUnderlyingType(member)); 
InBlock.gif
InBlock.gif               
if(converter==null || !converter.CanConvertFrom(paramValue.GetType())) 
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif  {//如果转换器为空或不能从字符串类型转换,抛出异常 
InBlock.gif

InBlock.gif                           
throw new ApplicationException( 
InBlock.gif
InBlock.gif                                    String.Format( 
InBlock.gif
InBlock.gif                                           
"Could not convert from {0}"
InBlock.gif
InBlock.gif                                            paramValue.GetType() 
InBlock.gif
InBlock.gif                                    ) 
InBlock.gif
InBlock.gif                        ); 
InBlock.gif
ExpandedSubBlockEnd.gif                  }
 
InBlock.gif
InBlock.gif  
InBlock.gif
InBlock.gif                 
try 
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif              
dot.gif{//将paramValue从字符串类型转换成 
InBlock.gif
InBlock.gif                     
//对应成员变量或属性的类型 
InBlock.gif

InBlock.gif                     typedValue
=converter.ConvertFrom(paramValue); 
InBlock.gif
InBlock.gif                     SetMemberValue(member, target, typedValue); 
InBlock.gif
InBlock.gif                     
//注:自定义SetMemberValue,将target.member的值 
InBlock.gif
InBlock.gif                     
//设为同类型的typedValue; 
InBlock.gif

ExpandedSubBlockEnd.gif                 }
 
InBlock.gif
InBlock.gif                 
catch 
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif               
dot.gif
InBlock.gif
InBlock.gif                     
// 这里捕获类型转换和在设置变量或属性中的异常错误 
InBlock.gif
InBlock.gif                     
//如果定义了缺省值,且确定当发生无效值时使用缺省值 
InBlock.gif
InBlock.gif                     
//设定变量或属性为缺省值 
InBlock.gif

InBlock.gif                     
if (!usingDefault && attrib.IsDefaultUsedForInvalid && attrib.DefaultValue!=null
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif                   
dot.gif
InBlock.gif
InBlock.gif                         typedValue  
=converter.ConvertFrom( attrib.DefaultValue); 
InBlock.gif
InBlock.gif                         SetMemberValue(member, target, typedValue); 
InBlock.gif
ExpandedSubBlockEnd.gif                     }
 
InBlock.gif
InBlock.gif                     
else 
InBlock.gif
InBlock.gif                         
throw
InBlock.gif
ExpandedSubBlockEnd.gif                 }
 
InBlock.gif
ExpandedSubBlockEnd.gif             }
 
InBlock.gif
ExpandedSubBlockEnd.gif         }
 
InBlock.gif
InBlock.gif         
catch(Exception err) 
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif         
dot.gif
InBlock.gif
InBlock.gif             
throw new ApplicationException( "Property/field {0} could not be set from request - " + err.Message,err); 
InBlock.gif
ExpandedSubBlockEnd.gif          }
 
InBlock.gif
ExpandedSubBlockEnd.gif     }
 
InBlock.gif
InBlock.gif  
InBlock.gif
InBlock.gif


 

²        GetValue方法

request中检索名paramName对应的值,返回字符串

None.gif protected   virtual   string  GetValue( string  paramName, System.Web.HttpRequest request) 
None.gif
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {//该函数可以重载,以支持Session,QueryString,Form,ViewState类型 
InBlock.gif

InBlock.gif         
if (request.HttpMethod.ToLower()=="post"
InBlock.gif
InBlock.gif             
return request.Form[paramName]; 
InBlock.gif
InBlock.gif         
else 
InBlock.gif
InBlock.gif             
return request.QueryString[paramName]; 
InBlock.gif
InBlock.gif     
InBlock.gif
ExpandedBlockEnd.gif}
 
None.gif
None.gif


 

²        GetMemberUnderlyingType方法

获取变量或属性对应的类型变量

None.gif private   static  Type GetMemberUnderlyingType(MemberInfo member) 
None.gif
ExpandedBlockStart.gifContractedBlock.gif
dot.gif
InBlock.gif
InBlock.gif
//获取member的Type类型对象,如果不是变量或属性,则抛出异常 
InBlock.gif
InBlock.gif
//注意:FiledInfo和PropertyInfo,MethodInfo都是MemberInfo的子类 
InBlock.gif

InBlock.gif     
switch(member.MemberType) 
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif     
dot.gif
InBlock.gif
InBlock.gif         
case MemberTypes.Field: 
InBlock.gif
InBlock.gif             
return ((FieldInfo)member).FieldType; 
InBlock.gif
InBlock.gif         
case MemberTypes.Property: 
InBlock.gif
InBlock.gif             
return ((PropertyInfo)member).PropertyType; 
InBlock.gif
InBlock.gif         
default
InBlock.gif
InBlock.gif             
throw new ArgumentException( 
InBlock.gif
InBlock.gif
"Expected a FieldInfo or PropertyInfo"
InBlock.gif
InBlock.gif
"member"); 
InBlock.gif
ExpandedSubBlockEnd.gif     }
 
InBlock.gif
InBlock.gif


²        SetMemberValue方法

根据变量或属性两种情况对成员进行赋值

None.gif private   static   void  SetMemberValue(MemberInfo member,  object  target,  object  value) 
None.gif
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {//对变量(Field)和属性(Property)的SetValue方法不太一样, 
InBlock.gif
InBlock.gif
//所以要分成两种情况考虑 
InBlock.gif

InBlock.gif  
InBlock.gif
InBlock.gif     
switch(member.MemberType) 
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif     
dot.gif
InBlock.gif
InBlock.gif         
case MemberTypes.Field: 
InBlock.gif
InBlock.gif             ((FieldInfo)member).SetValue(target, value); 
InBlock.gif
InBlock.gif             
break
InBlock.gif
InBlock.gif  
InBlock.gif
InBlock.gif         
case MemberTypes.Property: 
InBlock.gif
InBlock.gif             
// 我们已经知道该属性不是索引属性, 
InBlock.gif
InBlock.gif           
//所以该属性不会是数组,设置序号为0的属性就可以了 
InBlock.gif

InBlock.gif             ((PropertyInfo)member).SetValue( 
InBlock.gif
InBlock.gif                        target, 
InBlock.gif
InBlock.gif                       value, 
InBlock.gif
InBlock.gif                       
new Object[0]//对序号为0的属性设置 
InBlock.gif

InBlock.gif            ); 
InBlock.gif
InBlock.gif             
break
InBlock.gif
ExpandedSubBlockEnd.gif     }
 
InBlock.gif
ExpandedBlockEnd.gif}
 
None.gif
None.gif


五.     改进

为了实际解决QueryStringSession的参数化问题,对WebParameterAttribute类做了些修改,同时以WebParameterAttribute类为基类派生了QueryParameterAttribute类和SessionParameterAttribute,分别负责QueryStringSession的参数化。

具体做法如下:

WebParameterAttribute类中添加了两类静态函数,一类是用于从QueryStringSessionViewState中读取数据到Page类的成员变量中去。相应的实现函数分别是SetValuesFromBufferSetValueFromBufferSetMemberValue;另一类用于将Page类的成员变量值写入到SessionViewState的变量中去。相应的实现函数分别示SetValuesToBufferSetValueToBufferSetBufferValue。这两类函数的具体实现请看程序源代码,原理和前面讲述的一样。

六.     有待改进的地方

以参数BindingFlags.NonPublic调用Type.GetMembers方法时,系统规定反射代码只能存取被反射对象的protectedpublic访问类型的成员,要访问private成员,需要用到ReflectionPermission类赋于代码一定权限,而MSDN和其他的资料里关于如何使用ReflectionPermission类访问被反射对象的private成员语焉不详。所以目前本解决方案中还访问不到Page对象的private成员,而只能访问protectedpublic成员。

 

 

七.     技术文档

l         AttributeUsageAttribute

形如

MyTestvalue,attr1=value1,attr2=value2)]

的代码实际上是用类MyTestAttribute定义了一个对象MyTestAttribute(value),而value则是传递的构造函数的参数,可以不止一个,但是要按照定义构造函数时参数的顺序传递。而形如attr1=value1,attr2=value2,则是在MyTestAttribute类中定义了attr1,attr2属性(property),可以在生成MyTestAttribute的对象时给这些属性赋值,这是可选的。

因此,前面的代码表明了

[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple=false, Inherited=true)]

实际上是AttributeUsageAttribute类生成的一个对象,传递给构造函数的参数为AttributeTargets.Field | AttributeTargets.Property,同时给两个命名属性赋了值。

关于AttributeUsageAttributeMSDN里的说明是:定义您自己的特性类时,可通过在特性类上放置 AttributeUsageAttribute 来控制特性类的使用方式。指示的特性类必须直接或间接地从 Attribute 派生。

换句话说,我们定义一个自己的特性类WebParameterAttribute类时,要从Attribute派生,同时用AttributeUsageAttribute的对象来控制自己的WebParameterAttribute类将来可以怎样被使用。

向构造函数传递的参数为AttributeTargets类型的枚举变量,有以下几种组合:

Class:可以将自定义的特性类用于一个类

例:

None.gif [AttributeUsage(AttributeTargets.Class)]
None.gif
public   class  ClassTargetAttribute : Attribute
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
ExpandedBlockEnd.gif}

None.gif
None.gif[ClassTarget]
None.gif
public   class  TestClass
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
ExpandedBlockEnd.gif}

None.gif
None.gif
// 错误的用法
None.gif
[ClassTarget]
None.gif
public   int  CustomerID;
None.gif
// 因为ClassTargetAttribute由
None.gif
// [AttributeUsage(AttributeTargets.Class)]表明了只能用于类
None.gif

 

Field:可以将自定义的特性类用于一个成员变量

例:

None.gif [AttributeUsage(AttributeTargets.Field)]
None.gif
public   class  FieldTargetAttribute : Attribute
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
ExpandedBlockEnd.gif}

None.gif
None.gif[FieldTarget]
None.gif
public   int  Count;
None.gif

 

Property:可以将自定义的特性类用于一个属性

例:

[AttributeUsage(AttributeTargets.Property)]

public class PropertyTargetAttribute : Attribute

{

}

 

[PropertyTarget]

public string Name

{

     get{return m_name;}

     set{m_name=value;}

}

 

AttributeUsageAttribute的两个命名参数AllowMultiple=false, Inherited=true,其中AllowMultiple是指是否允许在同一个对象上多次使用自定义的属性类,而Inherited指明该属性是否可以有派生类:

例如:

[AttributeUsage(AttributeTargets.PropertyAllowMultiple=false)]

public class PropertyTargetAttributestring Name : Attribute

{

}

//错误的用法,因为AllowMultiple指明了

//不允许在同一对象上多次使用该属性

[PropertyTarget(John)]

[PropertyTarget(Tom) ]

class TestClass

{

}

 

 

l         获取类的类型信息

ToSetValues

1、             Type. GetMembers

当在派生类中重写时,使用指定绑定约束,搜索为当前 Type 定义的成员。

[Visual Basic]

Overloads Public MustOverride Function GetFields( _

   ByVal bindingAttr As BindingFlags _

) As FieldInfo() Implements IReflect.GetFields

[C#]

public abstract MemberInfo[] GetMembers(
   BindingFlags bindingAttr
);
 [Visual Basic]

Overloads Public MustOverride Function GetMembers( _

   ByVal bindingAttr As BindingFlags _

) As MemberInfo() Implements IReflect.GetMembers

[C#]

 [C++]

public: virtual MemberInfo* GetMembers(

   BindingFlags bindingAttr

) [] = 0;

[JScript]

public abstract function GetMembers(

   bindingAttr : BindingFlags

) : MemberInfo[];

 [C++]

public: virtual FieldInfo* GetFields(

   BindingFlags bindingAttr

) [] = 0;

[JScript]

public abstract function GetFields(

   bindingAttr : BindingFlags

) : FieldInfo[];

参数
可以使用下列 BindingFlags 筛选标志定义包含在搜索中的字段: 
为了获取返回值,必须指定 BindingFlags.Instance  BindingFlags.Static 
指定 BindingFlags.Public 可在搜索中包含公共字段。 
指定 BindingFlags.NonPublic 可在搜索中包含非公共字段(即私有字段和受保护的字段)。 
指定 BindingFlags.FlattenHierarchy 可包含层次结构上的静态成员。 
下列 BindingFlags 修饰符标志可用于更改搜索的执行方式: 
BindingFlags.DeclaredOnly,表示仅搜索在 Type 上声明的字段,
而不搜索简单继承的字段。 
注意 
  必须与 Public  NonPublic 一起指定 Instance  Static,否则将不返回成员。
有关更多信息,请参见 System.Reflection.BindingFlags

 

 

2、             MemberInfo. GetCustomAttributes

To:SetValue

在派生类中被重写时,返回由 Type 标识的自定义特性的数组。

[Visual Basic]

Overloads Public MustOverride Function GetCustomAttributes( _

   ByVal attributeType As Type, _

   ByVal inherit As Boolean _

) As Object() Implements ICustomAttributeProvider.GetCustomAttributes

[C#]

public abstract object[] GetCustomAttributes(
   Type attributeType,
   bool inherit
);
[C++]

public: virtual Object* GetCustomAttributes(

   Type* attributeType,

   bool inherit

)  __gc[] = 0;

[JScript]

public abstract function GetCustomAttributes(

   attributeType : Type,

   inherit : Boolean

) : Object[];

 

参数
attributeType 
要搜索的属性类型。只返回可分配给此类型的属性。 
inherit 
指定是否搜索该成员的继承链以查找这些属性。 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值