diff options
Diffstat (limited to 'src/System.Web.Mvc/ValueProviderResult.cs')
-rw-r--r-- | src/System.Web.Mvc/ValueProviderResult.cs | 163 |
1 files changed, 163 insertions, 0 deletions
diff --git a/src/System.Web.Mvc/ValueProviderResult.cs b/src/System.Web.Mvc/ValueProviderResult.cs new file mode 100644 index 00000000..3a15980b --- /dev/null +++ b/src/System.Web.Mvc/ValueProviderResult.cs @@ -0,0 +1,163 @@ +using System.Collections; +using System.ComponentModel; +using System.Globalization; +using System.Web.Mvc.Properties; + +namespace System.Web.Mvc +{ + [Serializable] + public class ValueProviderResult + { + private static readonly CultureInfo _staticCulture = CultureInfo.InvariantCulture; + private CultureInfo _instanceCulture; + + // default constructor so that subclassed types can set the properties themselves + protected ValueProviderResult() + { + } + + public ValueProviderResult(object rawValue, string attemptedValue, CultureInfo culture) + { + RawValue = rawValue; + AttemptedValue = attemptedValue; + Culture = culture; + } + + public string AttemptedValue { get; protected set; } + + public CultureInfo Culture + { + get + { + if (_instanceCulture == null) + { + _instanceCulture = _staticCulture; + } + return _instanceCulture; + } + protected set { _instanceCulture = value; } + } + + public object RawValue { get; protected set; } + + private static object ConvertSimpleType(CultureInfo culture, object value, Type destinationType) + { + if (value == null || destinationType.IsInstanceOfType(value)) + { + return value; + } + + // if this is a user-input value but the user didn't type anything, return no value + string valueAsString = value as string; + if (valueAsString != null && valueAsString.Trim().Length == 0) + { + return null; + } + + TypeConverter converter = TypeDescriptor.GetConverter(destinationType); + bool canConvertFrom = converter.CanConvertFrom(value.GetType()); + if (!canConvertFrom) + { + converter = TypeDescriptor.GetConverter(value.GetType()); + } + if (!(canConvertFrom || converter.CanConvertTo(destinationType))) + { + // EnumConverter cannot convert integer, so we verify manually + if (destinationType.IsEnum && value is int) + { + return Enum.ToObject(destinationType, (int)value); + } + + // In case of a Nullable object, we try again with its underlying type. + Type underlyingType = Nullable.GetUnderlyingType(destinationType); + if (underlyingType != null) + { + return ConvertSimpleType(culture, value, underlyingType); + } + + 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); + } + } + + public object ConvertTo(Type type) + { + return ConvertTo(type, null /* culture */); + } + + public virtual object ConvertTo(Type type, CultureInfo culture) + { + if (type == null) + { + throw new ArgumentNullException("type"); + } + + CultureInfo cultureToUse = culture ?? Culture; + return UnwrapPossibleArrayType(cultureToUse, RawValue, type); + } + + private static object UnwrapPossibleArrayType(CultureInfo culture, object value, Type destinationType) + { + if (value == null || destinationType.IsInstanceOfType(value)) + { + return value; + } + + // array conversion results in four cases, as below + Array valueAsArray = value as Array; + if (destinationType.IsArray) + { + Type destinationElementType = destinationType.GetElementType(); + if (valueAsArray != null) + { + // case 1: both destination + source type are arrays, so convert each element + 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 + { + // case 2: destination type is array but source is single element, so wrap element in array + convert + object element = ConvertSimpleType(culture, value, destinationElementType); + IList converted = Array.CreateInstance(destinationElementType, 1); + converted[0] = element; + return converted; + } + } + else if (valueAsArray != null) + { + // case 3: destination type is single element but source is array, so extract first element + convert + if (valueAsArray.Length > 0) + { + value = valueAsArray.GetValue(0); + return ConvertSimpleType(culture, value, destinationType); + } + else + { + // case 3(a): source is empty array, so can't perform conversion + return null; + } + } + // case 4: both destination + source type are single elements, so convert + return ConvertSimpleType(culture, value, destinationType); + } + } +} |