且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

白话学习MVC(六)模型绑定

更新时间:2022-09-17 19:35:02

一、什么是模型绑定?

  模型绑定存在的意义就是为Action的参数提供值,例如:如下表单中提交了数据,那么Action(即:Index)的参数Id,Name的值就是表单中对应的name属性相同的值,而表单提交的值是如何赋值给Action的参数的呢?模型绑定就是来完成从用户提交的请求中提取数据,并赋值给Action的参数。此例是从表单中的提取数据,并赋值给Action的参数,模型绑定还可以完成完成从地址Url、路由Route、上传文件等中获取数据,并赋值给Action相应的参数。

<form id="form0" action="../Home/Index" method="post">
    UserName:<input type="text" name="Id" />
    PassWord:<input type="text" name="Name" />
    <input type="submit" value="Submit"/>
</form>
        [HttpPost]//注意:参数名必须要和html标签中的name属性相同
        public ActionResult Index(string Id,string Name)
        {
            return Content(Id+Name);
        }

二、模型绑定机制介绍

  MVC中的模型绑定都是有默认的模型绑定DefaultModelBinder来完成,为清楚模型绑定的机制,我们来通过自定义模型绑定来由浅到深的学习
  模型绑定整个过程可以分为:从请求中获取数据、将请求中的数据转换成Action参数的类型并返回。
  模型绑定必须要实现IModelBinder接口,改接口中有唯一的返回值类型为object类型的方法BindModel,改方法的返回值就是相应的Action参数的值,那么可以这么理解,当接收到请求并在执行Action之前,要调用BindModel方法,在改方法的内部直接或简介的实现从请求中获取值,并返回给Action的参数。
  BindModel方法的参数:ControllerContext是当前Controller的上下文,即:封装了当前Controller和Route的相关信息;而ModelBindingContext则是当前绑定的参数类型的相关信息,例如有这么一个Action:public ActionResult Index(User use),此时ModelBindingContext就是参数use的相关信息。

    public interface IModelBinder
    {
        object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext);
    }

简单类型和复杂类型的模型绑定

  示例1:模型绑定机制

白话学习MVC(六)模型绑定
  public class MyModelBinder:IModelBinder
    {
        public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
        {
            return "获取的值并返回";
        }
    }
白话学习MVC(六)模型绑定
白话学习MVC(六)模型绑定
        [HttpPost]
        public ActionResult Index([ModelBinder(typeof(MyModelBinder))]string Temp1,[ModelBinder(typeof(MyModelBinder))]string Temp2)
        {
            return Content(Temp1+temp2);
        }      
     //[ModelBinder(typeof(MyModelBinder))]表示此处string类型的参数Temp的值由自定义的MyModelBinder提供
白话学习MVC(六)模型绑定

   此示例实现了对指定参数类型的模型绑定,在调用Action之前,对于每个参数都需要调用与之绑定的ModelBinder的BindModel方法来获取值,当然在我们的示例中,参数Temp1和Temp2各自都要执行一遍MyModelBinder的BindModel方法来获取相应的参数。
  但是,我们的参数是在BinderModel方法中直接写的,而在实际中我们是要从用户发来的请求中获取到的,由此我们由引出一个叫做ValueProvider的组件,直译就是值提供器,通过它来实现在请求中获取值。值提供器需要实现IValueProvider接口,默认的值提供器有:FormValueProvider、RouteDataValueProvider、 QueryStringValueProvider、 HttpFileCollectionValueProvider,分别是从表单、路由、地址字符串、上传文件中获取数据,既然同时存在这么多的ValueProvider,那么他们的调用肯定是有顺序的(就是按照上面写的顺序啦啦啦啦...),值得说的是,只要在找到一个值,那么就不再继续在其它的ValueProvider中找了。
IVaueProvider接口

    public interface IValueProvider
    {
        bool ContainsPrefix(string prefix);
        ValueProviderResult GetValue(string key);
    }

   ContainsPrefix方法用来判断是否包含前缀,GetValue方法则是用来获取值,并返回一个封装了获取的值和相关转换方法的ValueProviderResult类型。

  示例2:利用默认的ValueProvider实现自定义模型绑定

白话学习MVC(六)模型绑定
//Html
    <h2>Index</h2>
        <form id="form0" action="../Home/Index" method="post">
        <input type="text" name="Temp" /> 
        <input type="submit" value="Submit"/>  
    </form>

//Action
        [HttpPost]
        public ActionResult Index([ModelBinder(typeof(MyModelBinder))]string Temp)
        {
            return Content(Temp);
        }    

//自定义ModelBinder
    public class MyModelBinder:IModelBinder
    {
        public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
        {
            IValueProvider valueProvider = bindingContext.ValueProvider;
            string key = bindingContext.ModelName;
            Type modelType = bindingContext.ModelType;

            if (valueProvider.ContainsPrefix(key))
            {
                return valueProvider.GetValue(key).ConvertTo(modelType);
            }
            return null;
        }
    }
白话学习MVC(六)模型绑定

  此示例利用默认的ValueProvider从表单中获取标签的name属性为Temp的Text的数值,在自定义的BindModel方法中可以看出ModelBindingContext的的重要性,bindingContext.ValueProvider得到值提供器,bindingContext.ModelName得到的是绑定的Action方法中的参数名(此例中为:Temp),bindingContext.ModelType得到的是绑定的参数的类型(此例中为:string),valueProvider.ContainsPrefix(“Temp”)就是在全部的表单中检查是否存在这样name属性为Temp的标签,valueProvider.GetValue(key).ConvertTo(modelType)就是获取值并转换为Action参数的类型!----注意:默认的ContainsPrefix方法中,只有表单中存在Temp或Temp.才返回true

  示例3:利用自定义ValueProvider和自定义ModelBinder实现模型绑定

  • 利用自定义的ModelBinder,只需要在Action的参数前利用模型绑定的ModelBinder特性添加,否则使用默认的模型绑定DefaultModelBinder
  • 利用自定义的ValueProvider,需要新建一个自定义的ValueProviderFactory,在ValueProviderFactory的GetValueProvider方法中,实例化自定的ValueProvider并返回。
白话学习MVC(六)模型绑定
//自定义ModelBinder
    public class MyModelBinder:IModelBinder
    {
        public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
        {
            return bindingContext.ValueProvider.GetValue(bindingContext.ModelName).ConvertTo(bindingContext.ModelType);
        }
    }
//自定义ValueProvider
    public class MyValueProvider:IValueProvider
    {
        public bool ContainsPrefix(string prefix)
        {
            //暂时不写判断是否含有前缀的定义,因为貌似默认情况下,不是是否含有此前缀,而是是否含有此关键字
            return false;
        }
        public ValueProviderResult GetValue(string key)
        {
            string[] objResult = HttpContext.Current.Request.Form.GetValues(key);//获取表单中name属性是key的所有值,放入到一个字符串数组中
            string strResult = HttpContext.Current.Request.Form[key];
       //将原始值(数组),和值的字符串形式封装到一个ValueProviderResult中
            ValueProviderResult vpr = new ValueProviderResult(objResult, strResult, System.Globalization.CultureInfo.CurrentCulture);
            return vpr;
        }
    }    
//自定义ValueProviderFactory
    public class MyValueProviderFactory:ValueProviderFactory
    {
        public override IValueProvider GetValueProvider(ControllerContext controllerContext)
        {
            //此处构造了无参数的构造函数
            return new MyValueProvider();
        }
    }
//在程序启动时将自定义的ValueProvider添加到程序中
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();  
            RegisterGlobalFilters(GlobalFilters.Filters);
            RegisterRoutes(RouteTable.Routes);
            //因为在ValueProvider中,只要没有找到响应的值就会向下进行,所以我们将其他的ValueProvider移除
            ValueProviderFactories.Factories.RemoveAt(4);
            ValueProviderFactories.Factories.RemoveAt(3);
            ValueProviderFactories.Factories.RemoveAt(2);
            ValueProviderFactories.Factories.RemoveAt(1);
            ValueProviderFactories.Factories.RemoveAt(0);
            ValueProviderFactories.Factories.Insert(0,new MyValueProviderFactory());
            //ValueProviderFactories.Factories.Add(new MyValueProviderFactory());
        }
白话学习MVC(六)模型绑定

   此例利用自定义的ValueProvider来从请求中的表单中获取数据,并封装到一个ValueProviderResult中,而在自定义的ModelBinder中调用valueProvider,并得到其返回的ValueProviderResult类型的值,然后再利用ValueProviderResult的ConvertTo方法,将获取到的string[]类型转换为相应的类型(即:GetValue方法返回的是一个string[]类型),最终完成模型的绑定。但是在这个例子中我们没有在自定义的ValueProvider中写ContainsPrefix方法,当然程序中也没有用到他去判断,而是直接去利用GetValue方法去获取表单中的值。那么下面就来实现这个方法,并在程序中利用!

  示例4:自定义ModelBinder和自定义valueProvider(自己写ContainsPrefix方法)
上述的示例中都是对简单类型的模型绑定,下面我们就来写一个对复杂类型的绑定--->User类
User类
public class User
{
  public int ID{set;get;}
  public string Name{set;get;} 
}

白话学习MVC(六)模型绑定
//前台
<form id="form0" action="../Home/Index" method="post">

    <input type="text" name="use.Name" /> 
    <input type="text" name="Name" /> 

    <input type="submit" value="Submit"/>  
</form>

//Action
        [HttpPost]
        public ActionResult Index([ModelBinder(typeof(MyModelBinder))]User use, [ModelBinder(typeof(MyModelBinder))]User uu)
        {
            return Content(use.Id.ToString()+use.Name);
        }

//自定义的ModelBinder
 public class MyModelBinder:IModelBinder
    {
        public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
        {
           return GetModel(bindingContext.ValueProvider, bindingContext.ModelType, bindingContext.ModelName);   
        }
        public object GetModel(IValueProvider valueProvider, Type modelType, string modelName)
        {
            ModelMetadata modelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => null, modelType);
            //如果绑定的类型是简单类型
            if (!modelMetadata.IsComplexType)
            {
                return valueProvider.GetValue(modelName).ConvertTo(modelType);
            }
            object model = Activator.CreateInstance(modelType);
            //如果是复杂类型
            //前台表单标签的name属性的值有modelName的前缀
            if (valueProvider.ContainsPrefix(modelName))
            {
                foreach (PropertyDescriptor porperty in TypeDescriptor.GetProperties(modelType))
                {

                    string strkey = modelName + "." + porperty.Name;
                    if (HttpContext.Current.Request.Form.AllKeys.Contains<string>(strkey))
                        porperty.SetValue(model, valueProvider.GetValue(strkey).ConvertTo(porperty.PropertyType));
                }
            }
            //不包含前缀,但是标签的name属性的值等于绑定类的属性的名字
            else
            {
                foreach (PropertyDescriptor porperty in TypeDescriptor.GetProperties(modelType))
                {
                    string strkey = porperty.Name;
                    if (HttpContext.Current.Request.Form.AllKeys.Contains<string>(strkey))
                        porperty.SetValue(model, valueProvider.GetValue(strkey).ConvertTo(porperty.PropertyType));
                }
                
            }
            return model;
        }
    }

//自定义的ValueProvider
 public class MyValueProvider:IValueProvider
    {
        private string[] allKeys;

        public MyValueProvider(ControllerContext controllerContext)
        {
            allKeys = controllerContext.RequestContext.HttpContext.Request.Form.AllKeys;
        }

        public bool ContainsPrefix(string prefix)
        {
            foreach (string key in allKeys)
            {
                if (!key.Contains('.'))
                {
                    continue;
                }
                string[] temp = key.Split(new char[] { '.' });
                if (temp[0] == prefix)
                    return true;
            }
            return false;
        }
        public ValueProviderResult GetValue(string key)
        {
            string[] arrayResult = HttpContext.Current.Request.Form.GetValues(key);
            string strResult = HttpContext.Current.Request.Form[key];
            ValueProviderResult vpr = new ValueProviderResult(arrayResult, strResult, System.Globalization.CultureInfo.CurrentCulture);
            return vpr;
        }
    }
//自定义的ValueProviderFactory
    public class MyValueProviderFactory:ValueProviderFactory
    {
        public override IValueProvider GetValueProvider(ControllerContext controllerContext)
        {
            return new MyValueProvider(controllerContext);
            
        }
    }
//Global.asax文件
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();
            
            RegisterGlobalFilters(GlobalFilters.Filters);
            RegisterRoutes(RouteTable.Routes);

            ValueProviderFactories.Factories.RemoveAt(4);
            ValueProviderFactories.Factories.RemoveAt(3);
            ValueProviderFactories.Factories.RemoveAt(2);
            ValueProviderFactories.Factories.RemoveAt(1);
            ValueProviderFactories.Factories.RemoveAt(0);
            ValueProviderFactories.Factories.Insert(0, new MyValueProviderFactory());
        }
白话学习MVC(六)模型绑定

   此例中实现了对简单类型和复杂类型的绑定,在自定义的ModelBinder中,利用ModelMetadata来判定是否是复杂类型,并且利用反射来对指定类型进行实例化,再利用PorpertyDecript的循环来对类下的属性进行赋值。在自定义的ValueProvider中,在ContainsPrefix方法中实现了对请求中的是否包含指定前缀的判定。
  在这个自定义的ModelBinder中对复杂类型的绑定时,只能绑定上述User类那样的类型,但是在实际中还有存在嵌套类型的类,例如:
public class User
{
  public int Id{set;get;}
  public string Name{set;get;}
  public AAddress Address{set;get;}
}
public class AAddress
{
  public string province{set;get}
  public string City{set;get;}
  public string County{set;get;}
  public string Village{set;get;}
}


  示例5:利用递归完成对复杂类型的模型绑定。(注:相比于示例4,此处对多处多了修改,已完成对复杂类型绑定的支持)

白话学习MVC(六)模型绑定
//前台
<h2>Index</h2>
<form id="form0" action="../Home/Index" method="post">
    <table>
        <tr>
            <td><input type="text" name="Id" /> </td>
            <td><input type="text" name="Name" /></td>
            <td><input type="text" name="Address.province" /> </td>
            <td><input type="text" name="Address.City" /> </td>
        </tr>
        <tr>

            <td><input type="text" name="use.Address.City" /> </td>
            <td><input type="text" name="use.Address.County" /> </td>
        </tr>
        
    </table>
    <input type="submit" value="Submit"/>  
</form>

//自定义ModelBinder
    public class MyModelBinder:IModelBinder
    {
        public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
        {
           return GetModel(bindingContext.ValueProvider, bindingContext.ModelType, bindingContext.ModelName);   
        }
        public object GetModel(IValueProvider valueProvider, Type modelType, string modelName)
        {
            ModelMetadata modelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => null, modelType);
            //如果绑定的类型是简单类型
            if (!modelMetadata.IsComplexType)
            {
                return valueProvider.GetValue(modelName).ConvertTo(modelType);
            }
            object model = Activator.CreateInstance(modelType);
            //如果是复杂类型
            //如果表单中标签的name属性的值包含Action的参数名
            if (valueProvider.ContainsPrefix(modelName))
            {
                foreach (PropertyDescriptor properdty in TypeDescriptor.GetProperties(modelType))
                {
                    if (!valueProvider.ContainsPrefix(modelName + "." + properdty.Name))
                        continue;
                    ModelMetadata modelMetadataSon = ModelMetadataProviders.Current.GetMetadataForType(() => null, properdty.PropertyType);
                    if (!modelMetadataSon.IsComplexType)
                    {
                            properdty.SetValue(model, valueProvider.GetValue(modelName + "." + properdty.Name).ConvertTo(properdty.PropertyType));
                    }
                    else
                    {
                        properdty.SetValue(model, GetModel(valueProvider, properdty.PropertyType, modelName + "." + properdty.Name));
                    }
                }
            }
            else
            {
                foreach (PropertyDescriptor properdty in TypeDescriptor.GetProperties(modelType))
                {
                    if (!valueProvider.ContainsPrefix(properdty.Name))
                        continue;
                    ModelMetadata modelMetadataSon = ModelMetadataProviders.Current.GetMetadataForType(() => null, properdty.PropertyType);
                    if (!modelMetadataSon.IsComplexType)
                    {
                            properdty.SetValue(model, valueProvider.GetValue(properdty.Name).ConvertTo(properdty.PropertyType));
                    }
                    else
                    {
                        properdty.SetValue(model, GetModel(valueProvider, properdty.PropertyType,  properdty.Name));
                    }
                }
            }
            return model;
        }
    }

//自定义ValueProvider
    public class MyValueProvider:IValueProvider
    {
        private string[] allKeys;

        public MyValueProvider(ControllerContext controllerContext)
        {
            allKeys = controllerContext.RequestContext.HttpContext.Request.Form.AllKeys;
        }

        public bool ContainsPrefix(string prefix)
        {
            foreach (string key in allKeys)
            {
                if (key.Contains(prefix))
                    return true;
            }
            return false;
        }
        public ValueProviderResult GetValue(string key)
        {
            string[] arrayResult = HttpContext.Current.Request.Form.GetValues(key);
            string strResult = HttpContext.Current.Request.Form[key];
            ValueProviderResult vpr = new ValueProviderResult(arrayResult, strResult, System.Globalization.CultureInfo.CurrentCulture);
            return vpr;
        }
    }

//自定义ValueProviderFactory
    public class MyValueProviderFactory:ValueProviderFactory
    {
        public override IValueProvider GetValueProvider(ControllerContext controllerContext)
        {
            return new MyValueProvider(controllerContext);
            
        }
    }
白话学习MVC(六)模型绑定

  此示例中,完成了对复杂类型的模型绑定。流程为:如果表单中标签的name属性的值包含了Action参数的参数名,则对其类型的属性进行遍历,并将Action的参数名和遍历的类的当前属性拼接起来,作为key,通过ValueProvider向表单中获取值;如果表单中标签的name属性的值没有包含Action参数的参数名,则对类的属性进行遍历时,将遍历的类的当前属性名作为key,通过ValueProvider来向表单中获取值。
以上我们大体上完成了对简单类型和复杂类型的模型绑定,本着高内聚低耦合的思想,将上述中对简单类型和复杂类型的绑定重写规划下。

白话学习MVC(六)模型绑定 MyModelBinder

数组模型绑定

  在写自定义的数组类型模型绑定之前,先来看看默认情况下对数组的模型绑定是如何用的!

白话学习MVC(六)模型绑定 View Code

  在了解如何用默认的ModelBinder来完成数组类型的模型绑定,下面就来完成自定义ModelBinder来完成数组类型的模型绑定

白话学习MVC(六)模型绑定 View Code

  上例中:值得一说的是上例中的GetZeroBasedIndexes方法,它用来生成数字索引,方法利用了yield关键字,实现了延迟和按照上次进度继续执行的思想。


字典类型模型绑定
  利用默认ModelBinder的字典类型绑定

白话学习MVC(六)模型绑定 默认ModelBinder

  字典类型是指实现了IDictionary<key,value>借口的类型。
 在对字典类型进行模型绑定时,首先要判断绑定的类型是否是字典类型,如何来判断呢?

白话学习MVC(六)模型绑定

  如上图所示,对于字典类的模型绑定,需要判断两个条件:第一,是否为泛型;第二,判断构造当前泛型的泛型类型是否为IDictionary<,>,如果不是的话,再查找该类型是否继承IDictionary<,>接口(即:获取该泛型所继承的所有接口和类,再在这些类和接口中查找是否含有IDictionary<,>)。

白话学习MVC(六)模型绑定 自定义ModelBinder

 

集合类型模型绑定
  这里的集合指的是除了字典类型和数组类型意外,所有实现了IEnumerable借口的类型
  利用默认的ModelBinder来对集合类型进行模型绑定

白话学习MVC(六)模型绑定 View Code

  可以发现,利用默认的ModelBinder对集合类型的模型绑定和数组类型的模型绑定方式是一样的
  在对集合类型进行绑定时,首先要判断是否是泛型,再判断构造当前泛型的泛型类是否为IList<>或ICollection<>或IEnumerable<>  

注意:对集合类型的绑定的判断要放在数组和字典类之后,因为数组也是属于集合类,字典类型也继承自ICollection<T>(如下图)。所以,要在判断集合类之前,先判断是否为数组或字典类型。
白话学习MVC(六)模型绑定

   自定义集合类型的模型绑定

白话学习MVC(六)模型绑定 View Code

 

 

 

 以上就是个人整理的所有有关自定义的模型绑定的所有知识点,在最后对上述绑定中用到的几个重要的方法,来详细介绍下:

 一、 

     private static IEnumerable<string> GetZeroBasedIndexes()
        {
            int iteratorVariable0 = 0;
            while (true)
            {
                yield return iteratorVariable0.ToString();
                iteratorVariable0++;
            }
        } 
GetZeroBasedIndexes()方法,目的就是提供源源不断的自增1数字,并转换成字符串类型(因为模型绑定时,要对此产生的数据进行字符串拼接,所有直接转换成了string类型)。调用时的格式为:IEnumberable<string> indexes=GetZeroBaseIndexes();此时的indexes中什么都么有,在对indexes进行迭代时,才实时的执行GetZeroBasedIndexes方法,并且从上次执行的位置开始,继续执行。有关yield详细:yield介绍阿 
对于此方法的执行过程,可以自己断电测试下,就可以明白:

 二、

        public Type ExtractGenericInterface(Type queryType, Type interfaceType)
        {
            Func<Type, bool> predicate = t => t.IsGenericType && (t.GetGenericTypeDefinition() == interfaceType);
            if (predicate(queryType))
            {
                return queryType;
            }
            else
            {
                return queryType.GetInterfaces().FirstOrDefault<Type>(predicate);
            }

        }

ExtractGenericInterface方法用来判定类型是否为泛型,并且实现了指定的借口。对于方法内部包含的知识点有:1、FunC<T,TResult>,用来封装一个具有一个参数类型为T的参数并返回TResult类型的一个方法,该方法的参数参数为t,==>符号后面的就是内部逻辑。predicate(queryType),实质上就是执行FunC<,>封装的方法,参数为queryTyep;2、t.IsGenericType用来判断t类型是否为泛型;3、t.GetGenericTypeDefinition()方法用来获取构造泛型t的泛型类型(例:如果t为IList<string>,那么t的该方法就是IList<>);3、queryType.GetInterfaces()用来得到queryType类型继承的所有的类和实现的所有方法,返回值的类型为Type[]类型。4、.FirstOrDefault<Type>(predicate)则是用来在Type[]数组中获取第一个满足封装的方法perdicate条件的一个类型!

三、

    internal static class ReplaceHelper
    {

        private static MethodInfo replaceCollectionMethod = typeof(ReplaceHelper).GetMethod("ReplaceCollectionImpl", BindingFlags.Static | BindingFlags.NonPublic);

        public static void ReplaceCollection(Type collectionType, object collection, object newContents)
        {
            #region 
            ////将当前泛型方法定义的类型参数替换为类型数组的元素,并返回表示结果构造方法的MethodInfo对象
            ////即将当前泛型方法ReplaceCollectionImpl<T>中的T替换为collectionType,之后再去执行方法。状态变化:ReplaceCollectionImpl<T> --> ReplaceCollectionImpl<User>
            //MethodInfo m = replaceCollectionMethod.MakeGenericMethod(new Type[] { collectionType });

            //m.Invoke(null, new object[] { collection, newContents });//执行方法
            #endregion
            replaceCollectionMethod.MakeGenericMethod(new Type[] { collectionType }).Invoke(null, new object[] { collection, newContents });
        }
        private static void ReplaceCollectionImpl<T>(ICollection<T> collection, IEnumerable newContents)
        {
            collection.Clear();
            if (newContents != null)
            {
                foreach (object obj2 in newContents)
                {
                    T item = (obj2 is T) ? ((T)obj2) : default(T);
                    collection.Add(item);
                }
            }
        }
    }

此内部静态类的目的是将list中的数据,转换到指定集合中。由于replaceCollectionMethod是静态的变量,即当该类被加载时就通过反射得到一个MethodInfo类型的实例,之后的MakeGenericMethod方法做的是:将当前泛型方法定义的类型参数替换为类型数组的元素,并返回表示结果构造方法的MethodInfo对象,通俗的讲就是replaceCollectionMethod只是得到了方法,而通过MakeGenericMethod将泛型的参数再加入到通过反射得到的方法中,即状态变化为:ReplaceCollectionImpl<T> -->ReplaceCollectionImpl<collectionType>;之后再通过Invoke来激发通过反射要执行的方法(ReplaceCollectionImpl);在ReplaceCollectionImpl<T>方法内foreach循环便是将list类型向指定的集合类型转化的操作,其中default(T)是根据类型得到默认的值(例:int类型default(T)就是0,string类型default(T)就是null。即:根据类型得到默认值)

   

 以上就是本篇博客总结的模型绑定的全部,其中只对表单提交的值进行了操作!!

尼玛一不小心给搞成日记了,又重新贴了出来!!!

 


本文转自武沛齐博客园博客,原文链接:http://www.cnblogs.com/wupeiqi/p/3377854.html,如需转载请自行联系原作者