zoukankan      html  css  js  c++  java
  • MVC框架中的值提供机制(一)

         在MVC框架中action方法中的Model数据的绑定的来源有很多个,可能是http请求中的get参数或是post提交的表单数据,会是json字符串或是路径中的相关数据;MVC框架中针对这些不同的数据来源抽象了IValueProvider接口;

         

       public interface IValueProvider
       {
           bool ContainsPrefix(string prefix);
          ValueProviderResult GetValue(string key);
       }
      IValueProvider接口中的ContainsPrefix方法返回是否包含指定的前缀,GetValue方法时根据指定的key来获取相应的值数据结果;

    NameValueCollection
       NameValueCollection类时key和value都是字符串的字典,与Dictionary类型不同的是,一个key是可以对应多个值;
       NameValueCollection collection = new NameValueCollection();
       collection.Add("a", "aa");
       collection.Add("a", "bb");
       collection.Add("a", "cc");
       collection.Add("b", "aa");
       string[] rawValue = collection.GetValues("a");
       string attemptedValue = collection["a"];
       Console.WriteLine(attemptedValue);   // aa,bb,cc
       Console.WriteLine(rawValue);   // [aa,bb,cc]
       GetValues方法返回自定key的value的数组,attemptedValue 为指定key的value的字符串表示(项之间用,链接);

    ValueProviderResult
    ValueProviderResult类是存储Model数据的数据来源的值信息;msdn是这样描述的”表示将一个值(如窗体发布或查询字符串中的值)绑定到操作方法参数属性或绑定到该参数本身的结果“

         

     名称说明
    公共属性 AttemptedValue 获取或设置要转换为字符串,以便显示的原始值。
    公共属性 Culture 获取或设置区域性。
    公共属性 RawValue 获取或设置值提供程序所提供的原始值。

          在ValueProviderResult 类中含有一个ConvertTo(Type)方法,这个方法的目的是结果封装的值转换为指定的类型。在方法内部中将ValueProviderResult 类的RawValue转化为type类型的值数据。

         在ConvertTo(Type)方法内部实际上是调用的UnwrapPossibleArrayType 方法中的object value参数为RawValue,具体的处理逻辑如下:

          1.当value值为空或是当前对象value是当前类的实例(当前类可以是value 的类、父类、接口),直接返回value值;

          2.当Type的类型是数组类型时,首先会根据destinationType.GetElementType来获取数组元素的类型

               2.1 当value值能够转化为Array 数组时,然后根据转换Array 数组的长度和数组元素的类型通过Array.CreateInstance方法创建一个类型数组,最后逐个遍历转化数组的元素调用内部的ConvertSimpleType方法转换;

               2.2当value值不能够转化为Array数组时,type为数组类型时,首先调用内部ConvertSimpleType的方法获取到转换的值,然后创建一个长度为1的数组,将转换后的值写入到数组中。

         3.当Type类型不是数组类型时,并且Value的类型为数组类型时

              3.1当Value的类型为数组长度大于0时,获取到数组中的第一个元素值,调用内部ConvertSimpleType的方法获取到转换的值

              3.2当Value的类型为数组长度为0时,直接返回null值;

         4.当以上情况都不满足时,直接调用内部ConvertSimpleType的方法获取到转换的值

     private static object UnwrapPossibleArrayType(CultureInfo culture, object value, Type destinationType)
     {
          if (value == null || destinationType.IsInstanceOfType(value))
          {
             return value;
          }
          Array valueAsArray = value as Array;
          if (destinationType.IsArray)
          {
             Type destinationElementType = destinationType.GetElementType();
             if (valueAsArray != null)
             {
                 IList converted = Array.CreateInstance(destinationElementType, valueAsArray.Length);
                 for (int i = 0; i < valueAsArray.Length; i++)
                 {
                     converted[i] = ConvertSimpleType(culture, valueAsArray.GetValue(i), destinationElementType);
                 }
                 return converted;
             }
             else
             {
                 object element = ConvertSimpleType(culture, value, destinationElementType);
                 IList converted = Array.CreateInstance(destinationElementType, 1);
                 converted[0] = element;
                 return converted;
             }
          }
          else if (valueAsArray != null)
          {
             if (valueAsArray.Length > 0)
             {
                value = valueAsArray.GetValue(0);
                return ConvertSimpleType(culture, value, destinationType);
             }
             else
             {
                return null;
             }
           }
         return ConvertSimpleType(culture, value, destinationType);
     }

         在UnwrapPossibleArrayType 方法中经常会调用ConvertSimpleType方法,从字面意思上理解这个方法是进行简单类型的数组转换;

         1.当value值为空或是当前对象value是当前类的实例(当前类可以是value 的类、父类、接口),直接返回value值;

         2.当value值转换为字符串后为空字符串时直接返回null

         3.通过Nullable.GetUnderlyingType方法获取type是否是可空的值类型,如果是可空的值类型,则返回基础的值类型,当value值不是字符串类型时,value是否继承了IConvertible 接口,如果是,直接调用IConvertible 接口的ToType方法.

         4.当以上情况都不满足时,就会通过 TypeDescriptor.GetConverter类获取参数Type的类型转换器,获取到转换器后调用CanConvertFrom方法来获取value的type是否支持这个类型转换器,当不支持转换后,会获取value值的type类型的类型转换器;

           4.1如果不支持转换并且类型转换器不能转换到type,这时候就会throw 一个InvalidOperationException异常,不过一种情况除外,当类是枚举类型时,由于EnumConverter不能转换整数,所以我们手动转化,因此会调用Enum.ToObject方法;

           4.2如果类型转换器支持转换的话,就直接调用转换器的ConvertFrom的方法,否则调用ConvertTo方法来获取转化的值    

    private static object ConvertSimpleType(CultureInfo culture, object value, Type destinationType)
    {
          if (value == null || destinationType.IsInstanceOfType(value))
          {
             return value;
          }
          string valueAsString = value as string;
          if (valueAsString != null && String.IsNullOrWhiteSpace(valueAsString))
          {
             return null;
          }
           
    Type underlyingType = Nullable.GetUnderlyingType(destinationType); if (underlyingType != null) { destinationType = underlyingType; } if (valueAsString == null) { IConvertible convertible = value as IConvertible; if (convertible != null) { try { return convertible.ToType(destinationType, culture); } catch { } } } TypeConverter converter = TypeDescriptor.GetConverter(destinationType); bool canConvertFrom = converter.CanConvertFrom(value.GetType()); if (!canConvertFrom) { converter = TypeDescriptor.GetConverter(value.GetType()); } if (!(canConvertFrom || converter.CanConvertTo(destinationType))) { if (destinationType.IsEnum && value is int) { return Enum.ToObject(destinationType, (int)value); } string message = String.Format(CultureInfo.CurrentCulture, MvcResources.ValueProviderResult_NoConverterExists, value.GetType().FullName, destinationType.FullName); throw new InvalidOperationException(message); } try { object convertedValue = (canConvertFrom) ? converter.ConvertFrom(null /* context */, culture, value) : converter.ConvertTo(null /* context */, culture, value, destinationType); return convertedValue; } catch (Exception ex) { string message = String.Format(CultureInfo.CurrentCulture, MvcResources.ValueProviderResult_ConversionThrew, value.GetType().FullName, destinationType.FullName); throw new InvalidOperationException(message, ex); } }



     

  • 相关阅读:
    vue比较模板来跟新数据
    iframe自适应高度
    springmvc接口ios网络请求
    spring mvc实现接口参数统一更改
    spring mvc实现自定义注解
    基于redis集群实现的分布式锁,可用于秒杀,定时器。
    java使用javax.mail进行免费的邮件发送
    前端图片压缩上传(纯js的质量压缩,非长宽压缩)
    java项目中的路径获取,request
    阿里云(腾讯云类似)服务器控制台配置开放所有的端口
  • 原文地址:https://www.cnblogs.com/h20064528/p/5054868.html
Copyright © 2011-2022 走看看