Quiconque a utilisé la réflexion sait qu'appeler une méthode est très simple, mais comment préparer les paramètres entrants pour une méthode avec [signature inconnue] ?
Répondons à cette question ci-dessous. Veuillez examiner le processus d'implémentation de 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; }
Pour comprendre ce code, nous devons partir du [processus de recherche d'action] précédent. Vous pouvez obtenir la description d'une Action, qui est exprimée sous la forme du type ActionDescription à l'intérieur du framework :
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; } }
Dans la troisième ligne de code du constructeur , je peux obtenir tous les paramètres de cette méthode.
Ensuite, je peux boucler la définition de chaque paramètre dans la méthode GetActionCallParameters et leur attribuer des valeurs.
Ce code explique également la raison pour laquelle seuls 4 types de collections NameValueCollection sont pris en charge comme mentionné précédemment.
Remarque, lorsque j'obtiens le type de chaque paramètre, j'utilise l'instruction suivante :
Type paramterType = p.ParameterType.GetRealType();
En fait, ParameterType reflète déjà le type du paramètre, pourquoi pas directement. Qu'en est-il de l'utilisation il?
Réponse : à cause de [génériques nullables]. Ce type nécessite une manipulation particulière.
Par exemple : Si un paramètre est déclaré comme ceci : int? id
Alors, même si un paramètre comme id est inclus dans QueryString, je ne peux pas le convertir directement en int ? [type réel].
GetRealType() est une méthode d'extension qui remplit spécifiquement cette fonction :
/// <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; }
Si le type d'un paramètre est un type personnalisé, le framework créera d'abord une instance (appel sans paramètre constructeur), puis attribuez des valeurs à sa propriété et à son champ.
Remarque : les types personnalisés doivent fournir un constructeur sans paramètre.
Le code permettant de remplir les données membres pour une instance d'un type personnalisé est le suivant :
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模式下忽略异常(防止恶意用户错误输入) } } }
Avant de charger des données pour une instance de type de données personnalisé, vous devez connaître l'instance ObjetQuels sont les attributs et les champs ? Le code de ce processus est le suivant :
/// <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; }
Après avoir obtenu tous les attributs et informations de description de champ d'un type, vous pouvez le parcourir, accéder à QueryString et Form pour lire les données requises en fonction des noms de ces données membres.
【Recommandations associées】
1. Recommandation spéciale : Téléchargez la version V0.1 de "php Programmer Toolbox"
3 Exemple .NET MVC d'entrée de gamme
4.Explication détaillée du processus de recherche d'action dans la boîte MyMVC
5Explication détaillée du processus d'exécution d'action dans . NET MyMVC framework
6.Tutoriel sur la façon de gérer les valeurs de retour avec le framework .NET MyMVC
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!