ASP.NET视图的保存与加载解析(一)——视图的保存

ASP.NET在页面生命周期中有两个很重要的阶段分别是加载视图和保存视图,下面就设两个阶段作具体的讨论,最后讨论一下ASP.NET 2.0 引入的一个新的视图机制ConrolState

 

在读本文之前各位必须要清楚asp.net页面本身Page类就是个控件,所以下文中所指的控件既指Page本身也指包含在Page中的页面上的各个控件,另外本文讨论asp.net的两套视图机制一个就是大家熟悉的ViewState以下用视图二字表示,还有一套机制是asp.net 2.0新增的ConrolState以下用控件状态四个字在文中表示,请注意区分

 

1、视图的保存

                                                                                 图1

 

如图1 所示,视图在保存过程中会调用一个SaveAllState函数:

ExpandedBlockStart.gif 代码
private   void  SaveAllState()
{
    
if  ( this ._needToPersistViewState)
    {
        Pair state 
=   new  Pair();
        IDictionary dictionary 
=   null ;
        
if  (( this ._registeredControlsRequiringControlState  !=   null &&  ( this ._registeredControlsRequiringControlState.Count  >   0 ))
        {
            dictionary 
=   new  HybridDictionary( this ._registeredControlsRequiringControlState.Count  +   1 );
            
foreach  (Control control  in  (IEnumerable)  this ._registeredControlsRequiringControlState)
            {
                
object  obj2  =  control.SaveControlStateInternal();
                
if  ((dictionary[control.UniqueID]  ==   null &&  (obj2  !=   null ))
                {
                    dictionary.Add(control.UniqueID, obj2);
                }
            }
        }
        
if  (( this ._registeredControlsThatRequirePostBack  !=   null &&  ( this ._registeredControlsThatRequirePostBack.Count  >   0 ))
        {
            
if  (dictionary  ==   null )
            {
                dictionary 
=   new  HybridDictionary();
            }
            dictionary.Add(
" __ControlsRequirePostBackKey__ " this ._registeredControlsThatRequirePostBack);
        }
        
if  ((dictionary  !=   null &&  (dictionary.Count  >   0 ))
        {
            state.First 
=  dictionary;
        }
        Pair pair2 
=   new  Pair( this .GetTypeHashCode().ToString(NumberFormatInfo.InvariantInfo),  base .SaveViewStateRecursive());
        
if  ( this .Context.TraceIsEnabled)
        {
            
int  viewstateSize  =   0 ;
            
if  (pair2.Second  is  Pair)
            {
                viewstateSize 
=   base .EstimateStateSize(((Pair) pair2.Second).First);
            }
            
else   if  (pair2.Second  is  Triplet)
            {
                viewstateSize 
=   base .EstimateStateSize(((Triplet) pair2.Second).First);
            }
            
this .Trace.AddControlStateSize( this .UniqueID, viewstateSize, (dictionary  ==   null ?   0  :  base .EstimateStateSize(dictionary[ this .UniqueID]));
        }
        state.Second 
=  pair2;
        
this .SavePageStateToPersistenceMedium(state);
    }
}

 

从这段代码我们可以看出在LoadAllState中,ASP.NET最先使用了一个System.Web.Pair对象他有两个字段First、Second都是object类型

IDictionary dictionary = null;
if ((this._registeredControlsRequiringControlState != null) && (this._registeredControlsRequiringControlState.Count > 0))
{
    dictionary = new HybridDictionary(this._registeredControlsRequiringControlState.Count + 1);
    foreach (Control control in (IEnumerable) this._registeredControlsRequiringControlState)
    {
        object obj2 = control.SaveControlStateInternal();
        if ((dictionary[control.UniqueID] == null) && (obj2 != null))
        {
            dictionary.Add(control.UniqueID, obj2);
        }
    }
}
if ((this._registeredControlsThatRequirePostBack != null) && (this._registeredControlsThatRequirePostBack.Count > 0))
{
    if (dictionary == null)
    {
        dictionary = new HybridDictionary();
    }
    dictionary.Add("__ControlsRequirePostBackKey__", this._registeredControlsThatRequirePostBack);
}
if ((dictionary != null) && (dictionary.Count > 0))
{
    state.First = dictionary;
}

这段代码是用来读取页面所有的控件状态(最后再说这个)的,foreach (Control control in (IEnumerable) this._registeredControlsRequiringControlState)
将页面上所有注册要使用控件状态的控件进行遍历,然后
object obj2 = control.SaveControlStateInternal();
if ((dictionary[control.UniqueID] == null) && (obj2 != null))
{
  dictionary.Add(control.UniqueID, obj2);
}

将控件状态依次通过SaveControlStateInternal()读出来根据控件的唯一ID保存在一个散列集合dictionary里面,最后作为上面提到的Pair的First

继续深入那么在SaveControlStateInternal()里面又做了什么呢?

internal object SaveControlStateInternal()
{
    object x = this.SaveControlState();
    object y = null;
    if (this._adapter != null)
    {
        y = this._adapter.SaveAdapterControlState();
    }
    if ((x == null) && (y == null))
    {
        return null;
    }
    return new Pair(x, y);
}

这个函数做了两件事,首先通过SaveControlState读取控件状态,但是SaveControlState是个虚拟的空函数,而且你会发现里面就一句话retrun null,这说明如果要使用控件状态,控件状态的值从哪儿来得我们自己来实现(最后再说),接下来this._adapter != null如果控件适配器不为空,SaveControlStateInternal还使用了_adapter.SaveAdapterControlState在适配器类的角度来保存控件状态的逻辑,如果控件指定了适配器要自己实现相应的控件状态读取逻辑,最后根据X,Y的取值情况返回一个null或者Pair

接下来回到SaveAllState

Pair pair2 = new Pair(this.GetTypeHashCode().ToString(NumberFormatInfo.InvariantInfo), base.SaveViewStateRecursive());
if (this.Context.TraceIsEnabled)
{
    int viewstateSize = 0;
    if (pair2.Second is Pair)
    {
        viewstateSize = base.EstimateStateSize(((Pair) pair2.Second).First);
    }
    else if (pair2.Second is Triplet)
    {
        viewstateSize = base.EstimateStateSize(((Triplet) pair2.Second).First);
    }
    this.Trace.AddControlStateSize(this.UniqueID, viewstateSize, (dictionary == null) ? 0 : base.EstimateStateSize(dictionary[this.UniqueID]));
}
state.Second = pair2;

这段代码就是在读取视图状态,并且计算视图信息的大小,其中最核心的就是base.SaveViewStateRecursive(),这个函数会递归读取页面控件树的视图信息,请看:

internal object SaveViewStateRecursive()
{
    if (!this.flags[4])
    {
        object y = null;
        if (this._adapter != null)
        {
            y = this._adapter.SaveAdapterViewState();
        }
        object x = this.SaveViewState();
        ArrayList z = null;
        if (this.HasControls())
        {
            ControlCollection controls = this._occasionalFields.Controls;
            int count = controls.Count;
            bool loadViewStateByID = this.LoadViewStateByID;
            for (int i = 0; i < count; i++)
            {
                Control control = controls[i];
                object obj4 = control.SaveViewStateRecursive();
                if (obj4 != null)
                {
                    if (z == null)
                    {
                        z = new ArrayList(count);
                    }
                    if (loadViewStateByID)
                    {
                        control.EnsureID();
                        z.Add(control.ID);
                    }
                    else
                    {
                        z.Add(i);
                    }
                    z.Add(obj4);
                }
            }
        }
        if (this._adapter != null)
        {
            if (((x != null) || (y != null)) || (z != null))
            {
                return new Triplet(x, y, z);
            }
        }
        else if ((x != null) || (z != null))
        {
            return new Pair(x, z);
        }
    }
    return null;
}
此函数首先如果控件适配器不为空那么用this._adapter.SaveAdapterViewState()从适配器的角度读取视图信息,然后this.SaveViewState()一看便知是在读取控件本身的视图信息:

protected virtual object SaveViewState()
{
    if (this.flags[0x20])
    {
        this.ViewState["Visible"] = !this.flags[0x10];
    }
    if (this._viewState != null)
    {
        return this._viewState.SaveViewState();
    }
    return null;
}

this._viewState就是我们平时使用的ViewState集合,对他使用SaveViewState()将会把ViewState的每个值封装为一个ArrayList返回

回到SaveViewStateRecursive

 ArrayList z = null;
if (this.HasControls())
{
    ControlCollection controls = this._occasionalFields.Controls;
    int count = controls.Count;
    bool loadViewStateByID = this.LoadViewStateByID;
    for (int i = 0; i < count; i++)
    {
        Control control = controls[i];
        object obj4 = control.SaveViewStateRecursive();
        if (obj4 != null)
        {
            if (z == null)
            {
                z = new ArrayList(count);
            }
            if (loadViewStateByID)
            {
                control.EnsureID();
                z.Add(control.ID);
            }
            else
            {
                z.Add(i);
            }
            z.Add(obj4);
        }
    }
}

这是SaveViewStateRecursive里很重要的一个环节,即递归读取子控件的视图,HasControls可以判断该控件是否包含子控件,如果没有自然就不用递归了,ControlCollection controls = this._occasionalFields.Controls;会返回控件的子控件集合,然后依次对子控件递归调用object obj4 = control.SaveViewStateRecursive()将子控件视图返回为obj4,然后将子控件视图放入一个数组列表z,需要说明的是数组列表中控件的视图和控件本身是一对一对存在的,其中表示控件的值可以是控件的ID,也可以是控件在控件树中的索引:

if (loadViewStateByID)
{
  control.EnsureID();
  z.Add(control.ID);
}
else
{
  z.Add(i);
}
z.Add(obj4);

 如上所示先将控件的ID或索引放入z,紧接着再将控件的视图放入z

最后:
if (this._adapter != null)
{
    if (((x != null) || (y != null)) || (z != null))
    {
        return new Triplet(x, y, z);
    }
}
else if ((x != null) || (z != null))
{
    return new Pair(x, z);
}
如果控件适配器、控件自己、控件的子控件都取到视图值就将这三个元素的视图封装成一个Triplet对象(类似Pair只不过有三个object成员),如果没有取到适配器的视图就将控件自己的视图和子控件的视图封装成Pair返回,不管以哪种形式返回视图,我们心中都要有这么个概念,返回的视图信息是树状结构,其结构是根据控件树来递归确定的。

 

回到SaveAllState

最后将控件状态和视图封装成一个Pair对象state

state.First = dictionary;
//..........

state.Second = pair2;
this.SavePageStateToPersistenceMedium(state);

 

再调用SavePageStateToPersistenceMedium(state)

 protected internal virtual void SavePageStateToPersistenceMedium(object state)
{
    PageStatePersister pageStatePersister = this.PageStatePersister;
    if (state is Pair)
    {
        Pair pair = (Pair) state;
        pageStatePersister.ControlState = pair.First;
        pageStatePersister.ViewState = pair.Second;
    }
    else
    {
        pageStatePersister.ViewState = state;
    }
    pageStatePersister.Save();
}

SavePageStateToPersistenceMedium将state的控件状态和视图取出构造了一个PageStatePersister对象,这个对象有两个很重要的属性ControlState 和ViewState

pageStatePersister.ControlState = pair.First;
pageStatePersister.ViewState = pair.Second;

 

最后将pageStatePersister.Save()序列化并将序列化的信息作为网页上的input保存在客户端,整个视图保存的流程就完成了
保存在页面上的序列化信息相信大家已经很熟悉了:

<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="/wEPDwUJNzYwOTI5OTA4ZGQrXkI1DTujGF3xmo0Bgq2iNeJ0vQ==" />
所以大家必要被name="__VIEWSTATE" id="__VIEWSTATE"迷惑了,这个input里面不光有ViewState的值还有ControlState的值

转载于:https://www.cnblogs.com/OpenCoder/archive/2010/01/18/1650600.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1 目标检测的定义 目标检测(Object Detection)的任务是找出图像中所有感兴趣的目标(物体),确定它们的类别和位置,是计算机视觉领域的核心问题之一。由于各类物体有不同的外观、形状和姿态,加上成像时光照、遮挡等因素的干扰,目标检测一直是计算机视觉领域最具有挑战性的问题。 目标检测任务可分为两个关键的子任务,目标定位和目标分类。首先检测图像中目标的位置(目标定位),然后给出每个目标的具体类别(目标分类)。输出结果是一个边界框(称为Bounding-box,一般形式为(x1,y1,x2,y2),表示框的左上角坐标和右下角坐标),一个置信度分数(Confidence Score),表示边界框中是否包含检测对象的概率和各个类别的概率(首先得到类别概率,经过Softmax可得到类别标签)。 1.1 Two stage方法 目前主流的基于深度学习的目标检测算法主要分为两类:Two stage和One stage。Two stage方法将目标检测过程分为两个阶段。第一个阶段是 Region Proposal 生成阶段,主要用于生成潜在的目标候选框(Bounding-box proposals)。这个阶段通常使用卷积神经网络(CNN)从输入图像中提取特征,然后通过一些技巧(如选择性搜索)来生成候选框。第二个阶段是分类和位置精修阶段,将第一个阶段生成的候选框输入到另一个 CNN 中进行分类,并根据分类结果对候选框的位置进行微调。Two stage 方法的优点是准确度较高,缺点是速度相对较慢。 常见Tow stage目标检测算法有:R-CNN系列、SPPNet等。 1.2 One stage方法 One stage方法直接利用模型提取特征值,并利用这些特征值进行目标的分类和定位,不需要生成Region Proposal。这种方法的优点是速度快,因为省略了Region Proposal生成的过程。One stage方法的缺点是准确度相对较低,因为它没有对潜在的目标进行预先筛选。 常见的One stage目标检测算法有:YOLO系列、SSD系列和RetinaNet等。 2 常见名词解释 2.1 NMS(Non-Maximum Suppression) 目标检测模型一般会给出目标的多个预测边界框,对成百上千的预测边界框都进行调整肯定是不可行的,需要对这些结果先进行一个大体的挑选。NMS称为非极大值抑制,作用是从众多预测边界框中挑选出最具代表性的结果,这样可以加快算法效率,其主要流程如下: 设定一个置信度分数阈值,将置信度分数小于阈值的直接过滤掉 将剩下框的置信度分数从大到小排序,选中值最大的框 遍历其余的框,如果和当前框的重叠面积(IOU)大于设定的阈值(一般为0.7),就将框删除(超过设定阈值,认为两个框的里面的物体属于同一个类别) 从未处理的框中继续选一个置信度分数最大的,重复上述过程,直至所有框处理完毕 2.2 IoU(Intersection over Union) 定义了两个边界框的重叠度,当预测边界框和真实边界框差异很小时,或重叠度很大时,表示模型产生的预测边界框很准确。边界框A、B的IOU计算公式为: 2.3 mAP(mean Average Precision) mAP即均值平均精度,是评估目标检测模型效果的最重要指标,这个值介于0到1之间,且越大越好。mAP是AP(Average Precision)的平均值,那么首先需要了解AP的概念。想要了解AP的概念,还要首先了解目标检测中Precision和Recall的概念。 首先我们设置置信度阈值(Confidence Threshold)和IoU阈值(一般设置为0.5,也会衡量0.75以及0.9的mAP值): 当一个预测边界框被认为是True Positive(TP)时,需要同时满足下面三个条件: Confidence Score > Confidence Threshold 预测类别匹配真实值(Ground truth)的类别 预测边界框的IoU大于设定的IoU阈值 不满足条件2或条件3,则认为是False Positive(FP)。当对应同一个真值有多个预测结果时,只有最高置信度分数的预测结果被认为是True Positive,其余被认为是False Positive。 Precision和Recall的概念如下图所示: Precision表示TP与预测边界框数量的比值 Recall表示TP与真实边界框数量的比值 改变不同的置信度阈值,可以获得多组Precision和Recall,Recall放X轴,Precision放Y轴,可以画出一个Precision-Recall曲线,简称P-R
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值