.NET MyMVC框架如何给方法赋值的教程

Y2J
发布: 2017-05-17 11:28:05
原创
1915人浏览过

用过反射的人都知道,调用一个方法很简单,但如何给一个【不知签名】的方法准备传入参数呢?
下面就来回答这个问题,请接着看getactioncallparameters的实现过程:

private static object[] GetActionCallParameters(HttpContext context, ActionDescription action)
{    if( action.Parameters == null || action.Parameters.Length == 0 )        return null;    object[] parameters = new object[action.Parameters.Length];    for( int i = 0; i < action.Parameters.Length; i++ ) {        ParameterInfo p = action.Parameters[i];        if( p.IsOut )            continue;        if( p.ParameterType == typeof(NameValueCollection) ) {            if( string.Compare(p.Name, "Form", StringComparison.OrdinalIgnoreCase) == 0 )
                parameters[i] = context.Request.Form;            else if( string.Compare(p.Name, "QueryString", StringComparison.OrdinalIgnoreCase) == 0 )
                parameters[i] = context.Request.QueryString;            else if( string.Compare(p.Name, "Headers", StringComparison.OrdinalIgnoreCase) == 0 )
                parameters[i] = context.Request.Headers;            else if( string.Compare(p.Name, "ServerVariables", StringComparison.OrdinalIgnoreCase) == 0 )
                parameters[i] = context.Request.ServerVariables;
        }        else{            Type paramterType = p.ParameterType.GetRealType();            // 如果参数是简单类型,则直接从HttpRequest中读取并赋值            if( paramterType.IsSimpleType() ) {                object val = ModelHelper.GetValueByKeyAndTypeFrommRequest(
                                                context.Request, p.Name, paramterType, null);                if( val != null )
                    parameters[i] = val;
            }            else {                // 自定义的类型。首先创建实例,然后给所有成员赋值。
                // 注意:这里不支持嵌套类型的自定义类型。                object item = Activator.CreateInstance(paramterType);                ModelHelper.FillModel(context.Request, item, p.Name);
                parameters[i] = item;
            }
        }
    }    return parameters;
}
登录后复制

要理解这段代码还要从前面的【查找Action的过程】说起,在那个阶段,可以获取一个Action的描述,具体在框架内部表示为ActionDescription类型:

internal sealed class ActionDescription : BaseDescription{    public ControllerDescription PageController; //为PageAction保留    public MethodInfo MethodInfo { get; private set; }    public ActionAttribute Attr { get; private set; }    public ParameterInfo[] Parameters { get; private set; }    public bool HasReturn { get; private set; }    public ActionDescription(MethodInfo m, ActionAttribute atrr) : base(m)
    {        this.MethodInfo = m;        this.Attr = atrr;        this.Parameters = m.GetParameters();        this.HasReturn = m.ReturnType != ReflectionHelper.VoidType;
    }
}
登录后复制

构造函数的第三行代码中,我就可以得到这个方法的所有参数情况。
然后,我在就可以在GetActionCallParameters方法中,循环每个参数的定义,为它们赋值。
这段代码也解释了前面所说的只支持4种NameValueCollection集合的原因。

注意了,我在获取每个参数的类型时,是使用了下面的语句:

Type paramterType = p.ParameterType.GetRealType();
登录后复制

实际上,ParameterType就已经反映了参数的类型,为什么不直接使用它呢?
答:因为【可空泛型】的原因。这个类型我们需要特殊的处理。
例如:如果某个参数是这样声明的: int? id 
那么,即使在QueryString中包含id这样一个参数,我也不能直接转成 int? 使用这种类型,必须得到它的【实际类型】。
GetRealType()是个扩展方法,它就专门完成这个功能:

/// <summary>
/// 得到一个实际的类型(排除Nullable类型的影响)。比如:int? 最后将得到int/// </summary>
/// <param name="type"></param>
/// <returns></returns>public static Type GetRealType(this Type type)
{    if( type.IsGenericType )        return Nullable.GetUnderlyingType(type) ?? type;    else
        return type;
}
登录后复制

如果某个参数的类型是一个自定义的类型,框架会先创建实例(调用无参的构造函数),然后给它的Property, Field赋值。

注意了:自定义的类型,一定要提供一个无参的构造函数。

为自定义类型的实例填充数据成员的代码如下:

internal static class ModelHelper{    public static readonly bool IsDebugMode;    static ModelHelper()
    {        CompilationSection configSection = 
                    ConfigurationManager.GetSection("system.web/compilation") as CompilationSection;        if( configSection != null )
            IsDebugMode = configSection.Debug;
    }    /// <summary>
    /// 根据HttpRequest填充一个数据实体。    /// 这里不支持嵌套类型的数据实体,且要求各数据成员都是简单的数据类型。    /// </summary>
    /// <param name="request"></param>
    /// <param name="model"></param>    public static void FillModel(HttpRequest request, object model, string paramName)
    {        ModelDescripton descripton = ReflectionHelper.GetModelDescripton(model.GetType());        object val = null;        foreach( DataMember field in descripton.Fields ) {            // 这里的实现方式不支持嵌套类型的数据实体。
            // 如果有这方面的需求,可以将这里改成递归的嵌套调用。            val = GetValueByKeyAndTypeFrommRequest(
                                request, field.Name, field.Type.GetRealType(), paramName);            if( val != null )
                field.SetValue(model, val);
        }
    }    /// <summary>
    /// 读取一个HTTP参数值。这里只读取QueryString以及Form    /// </summary>
    /// <param name="request"></param>
    /// <param name="key"></param>
    /// <returns></returns>    public static string GetHttpValue(HttpRequest request, string key)
    {        string val = request.QueryString[key];        if( val == null )
            val = request.Form[key];        return val;
    }    
    public static object GetValueByKeyAndTypeFrommRequest(                        HttpRequest request, string key, Type type, string paramName)
    {        // 不支持复杂类型        if( type.IsSimpleType() == false )            return null;        string val = GetHttpValue(request, key);        if( val == null ) {            // 再试一次。有可能是多个自定义类型,Form表单元素采用变量名做为前缀。            if( string.IsNullOrEmpty(paramName) == false ) {
                val = GetHttpValue(request, paramName + "." + key);
            }            if( val == null )                return null;
        }        return SafeChangeType(val.Trim(), type);
    }    public static object SafeChangeType(string value, Type conversionType)
    {        if( conversionType == typeof(string) )            return value;        if( value == null || value.Length == 0 )            // 空字符串根本不能做任何转换,所以直接返回null            return null;        try {            // 为了简单,直接调用 .net framework中的方法。
            // 如果转换失败,则会抛出异常。            return Convert.ChangeType(value, conversionType);
        }        catch {            if( IsDebugMode )                throw;            // Debug 模式下抛异常            else
                return null;    // Release模式下忽略异常(防止恶意用户错误输入)        }
    }
}
登录后复制

在给自定义的数据类型实例加载数据前,需要先知道这个实例对象有哪些属性以及字段,这个过程的代码如下:

/// <summary>
/// 返回一个实体类型的描述信息(全部属性及字段)。/// </summary>
/// <param name="type"></param>
/// <returns></returns>public static ModelDescripton GetModelDescripton(Type type)
{    if( type == null )        throw new ArgumentNullException("type");    
    string key = type.FullName;    ModelDescripton mm = (ModelDescripton)s_modelTable[key];    if( mm == null ) {        List<DataMember> list = new List<DataMember>();
        (from p in type.GetProperties(BindingFlags.Instance | BindingFlags.Public)         select new PropertyMember(p)).ToList().ForEach(x=>list.Add(x));
        (from f in type.GetFields(BindingFlags.Instance | BindingFlags.Public)         select new FieldMember(f)).ToList().ForEach(x => list.Add(x));
        mm = new ModelDescripton { Fields = list.ToArray() };
        s_modelTable[key] = mm;
    }    return mm;
}
登录后复制

在拿到一个类型的所有属性以及字段的描述信息后,就可以通过循环的方式,根据这些数据成员的名字去QueryString,Form读取所需的数据了。

法语写作助手
法语写作助手

法语助手旗下的AI智能写作平台,支持语法、拼写自动纠错,一键改写、润色你的法语作文。

法语写作助手 31
查看详情 法语写作助手

【相关推荐】

1. 特别推荐“php程序员工具箱”V0.1版本下载

2. ASP免费视频教程

3.  入门级的.NET MVC 实例

4. MyMVC框查找Action的过程详解

5. .NET MyMVC框架执行Action的过程详解

6. .NET MyMVC框架处理返回值的教程

以上就是.NET MyMVC框架如何给方法赋值的教程的详细内容,更多请关注php中文网其它相关文章!

最佳 Windows 性能的顶级免费优化软件
最佳 Windows 性能的顶级免费优化软件

每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。

下载
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号