File: ModelBinding\ValueProviderResult.cs
Project: ndp\fx\src\xsp\system\Web\System.Web.csproj (System.Web)
namespace System.Web.ModelBinding {
    using System;
    using System.Collections;
    using System.ComponentModel;
    using System.Globalization;
 
    [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, SR.GetString(SR.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, SR.GetString(SR.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);
        }
 
    }
}