Tweaks to Enum::FormatName to make it faster/smaller
[mono.git] / mcs / class / System.Web.Mvc2 / System.Web.Mvc / ValueProviderResult.cs
1 /* ****************************************************************************\r
2  *\r
3  * Copyright (c) Microsoft Corporation. All rights reserved.\r
4  *\r
5  * This software is subject to the Microsoft Public License (Ms-PL). \r
6  * A copy of the license can be found in the license.htm file included \r
7  * in this distribution.\r
8  *\r
9  * You must not remove this notice, or any other, from this software.\r
10  *\r
11  * ***************************************************************************/\r
12 \r
13 namespace System.Web.Mvc {\r
14     using System;\r
15     using System.Collections;\r
16     using System.ComponentModel;\r
17     using System.Globalization;\r
18     using System.Web.Mvc.Resources;\r
19 \r
20     [Serializable]\r
21     public class ValueProviderResult {\r
22 \r
23         private static readonly CultureInfo _staticCulture = CultureInfo.InvariantCulture;\r
24         private CultureInfo _instanceCulture;\r
25 \r
26         // default constructor so that subclassed types can set the properties themselves\r
27         protected ValueProviderResult() {\r
28         }\r
29 \r
30         public ValueProviderResult(object rawValue, string attemptedValue, CultureInfo culture) {\r
31             RawValue = rawValue;\r
32             AttemptedValue = attemptedValue;\r
33             Culture = culture;\r
34         }\r
35 \r
36         public string AttemptedValue {\r
37             get;\r
38             protected set;\r
39         }\r
40 \r
41         public CultureInfo Culture {\r
42             get {\r
43                 if (_instanceCulture == null) {\r
44                     _instanceCulture = _staticCulture;\r
45                 }\r
46                 return _instanceCulture;\r
47             }\r
48             protected set {\r
49                 _instanceCulture = value;\r
50             }\r
51         }\r
52 \r
53         public object RawValue {\r
54             get;\r
55             protected set;\r
56         }\r
57 \r
58         private static object ConvertSimpleType(CultureInfo culture, object value, Type destinationType) {\r
59             if (value == null || destinationType.IsInstanceOfType(value)) {\r
60                 return value;\r
61             }\r
62 \r
63             // if this is a user-input value but the user didn't type anything, return no value\r
64             string valueAsString = value as string;\r
65             if (valueAsString != null && valueAsString.Trim().Length == 0) {\r
66                 return null;\r
67             }\r
68 \r
69             TypeConverter converter = TypeDescriptor.GetConverter(destinationType);\r
70             bool canConvertFrom = converter.CanConvertFrom(value.GetType());\r
71             if (!canConvertFrom) {\r
72                 converter = TypeDescriptor.GetConverter(value.GetType());\r
73             }\r
74             if (!(canConvertFrom || converter.CanConvertTo(destinationType))) {\r
75                 string message = String.Format(CultureInfo.CurrentUICulture, MvcResources.ValueProviderResult_NoConverterExists,\r
76                     value.GetType().FullName, destinationType.FullName);\r
77                 throw new InvalidOperationException(message);\r
78             }\r
79 \r
80             try {\r
81                 object convertedValue = (canConvertFrom) ?\r
82                      converter.ConvertFrom(null /* context */, culture, value) :\r
83                      converter.ConvertTo(null /* context */, culture, value, destinationType);\r
84                 return convertedValue;\r
85             }\r
86             catch (Exception ex) {\r
87                 string message = String.Format(CultureInfo.CurrentUICulture, MvcResources.ValueProviderResult_ConversionThrew,\r
88                     value.GetType().FullName, destinationType.FullName);\r
89                 throw new InvalidOperationException(message, ex);\r
90             }\r
91         }\r
92 \r
93         public object ConvertTo(Type type) {\r
94             return ConvertTo(type, null /* culture */);\r
95         }\r
96 \r
97         public virtual object ConvertTo(Type type, CultureInfo culture) {\r
98             if (type == null) {\r
99                 throw new ArgumentNullException("type");\r
100             }\r
101 \r
102             CultureInfo cultureToUse = culture ?? Culture;\r
103             return UnwrapPossibleArrayType(cultureToUse, RawValue, type);\r
104         }\r
105 \r
106         private static object UnwrapPossibleArrayType(CultureInfo culture, object value, Type destinationType) {\r
107             if (value == null || destinationType.IsInstanceOfType(value)) {\r
108                 return value;\r
109             }\r
110 \r
111             // array conversion results in four cases, as below\r
112             Array valueAsArray = value as Array;\r
113             if (destinationType.IsArray) {\r
114                 Type destinationElementType = destinationType.GetElementType();\r
115                 if (valueAsArray != null) {\r
116                     // case 1: both destination + source type are arrays, so convert each element\r
117                     IList converted = Array.CreateInstance(destinationElementType, valueAsArray.Length);\r
118                     for (int i = 0; i < valueAsArray.Length; i++) {\r
119                         converted[i] = ConvertSimpleType(culture, valueAsArray.GetValue(i), destinationElementType);\r
120                     }\r
121                     return converted;\r
122                 }\r
123                 else {\r
124                     // case 2: destination type is array but source is single element, so wrap element in array + convert\r
125                     object element = ConvertSimpleType(culture, value, destinationElementType);\r
126                     IList converted = Array.CreateInstance(destinationElementType, 1);\r
127                     converted[0] = element;\r
128                     return converted;\r
129                 }\r
130             }\r
131             else if (valueAsArray != null) {\r
132                 // case 3: destination type is single element but source is array, so extract first element + convert\r
133                 if (valueAsArray.Length > 0) {\r
134                     value = valueAsArray.GetValue(0);\r
135                     return ConvertSimpleType(culture, value, destinationType);\r
136                 }\r
137                 else {\r
138                     // case 3(a): source is empty array, so can't perform conversion\r
139                     return null;\r
140                 }\r
141             }\r
142             // case 4: both destination + source type are single elements, so convert\r
143             return ConvertSimpleType(culture, value, destinationType);\r
144         }\r
145 \r
146     }\r
147 }\r