上一篇我们在将ControllerDescriptor的时候,顺便提了一下该类里面的FindAction方法,这个方法返回的对象就是ActionDescriptor对象。顾名思义ActionDescriptor就是Action的描述对象,我们知道多个Action方法就组成了一个Controller集合,那么每一个Action就用ActionDescriptor来描述。老规矩我们先来看看ActionDescript里面的一些主要的成员吧:
public abstract string ActionName {get;} public abstract ControllerDescriptor ControllerDescriptor {get;} public virtual string UniqueId {get {return _uniqueId.Value;}} public virtual object[] GetCustomAttributes(bool inherit) {return GetCustomAttributes(typeof(object), inherit);} public virtual object[] GetCustomAttributes(Type attributeType, bool inherit) {} internal virtual IEnumerable<FilterAttribute> GetFilterAttributes(bool useCache) { return GetCustomAttributes(typeof(FilterAttribute), inherit: true).Cast<FilterAttribute>(); } public virtual FilterInfo GetFilters() {return new FilterInfo();} public abstract ParameterDescriptor[] GetParameters(); |
通过ActionDescriptor的相关属性我们可以知道和ControllerDescriptor一样,ActionDescriptor也有包含Action的名字,来源于路由信息;同时也包含一个string类型的UniqueId用于标识唯一的Action。并且可以通过GetCustomAttributes方法来获取应用在Action上面的标注特性(在ControllerDescriptor类中也有这个方法,原理都一样)。我们重点来看看GetParameters()这个抽象方法,由类ReflectedActionDescriptor重写了该方法:
//通过方法GetParameters返回的用于描述所有参数的ParameterDescriptor数组,也是通过对Action方法的参数列表进行反射来创建的 public override ParameterDescriptor[] GetParameters() { ParameterDescriptor[] parameters = LazilyFetchParametersCollection(); //need to clone array so that user modifications aren't accidentally stored return (ParameterDescriptor[])parameters.Clone(); } |
最终调用的是LazilyFetchParametersCollection(),具体如下:
private ParameterDescriptor[] LazilyFetchParametersCollection() { return DescriptorUtil.LazilyFetchOrCreateDescriptors<ParameterInfo, ParameterDescriptor>( ref _parametersCache /* cacheLocation */, MethodInfo.GetParameters /* initializer */, parameterInfo => new ReflectedParameterDescriptor(parameterInfo, this) /* converter */); } |
这里涉及到另外的一个类ReflectedParameterDescriptor,该类继承了ParameterDescriptor抽象类,ParameterDescriptor和ActionDescriptor,ControllerDescriptor类一样,都是包含了对应的参数,方法和控制器的相关信息。和ControllerDescriptor一样,我们也只需要了解ActionDescriptor包含的信息即可,后面我们将会重点介绍ParameterDescriptor类。
这样的话,在ControllerActionInvoker中的InvokeAction方法中我们就可以根据FindAction方法获取到了ActionDescriptor对象。