3
3
4
4
using System ;
5
5
using System . Collections ;
6
+ using System . ComponentModel ;
6
7
using System . Globalization ;
7
8
using System . Reflection ;
8
9
@@ -53,7 +54,7 @@ public virtual object ConvertTo([NotNull] Type type, CultureInfo culture)
53
54
if ( value == null )
54
55
{
55
56
// treat null route parameters as though they were the default value for the type
56
- return type . GetTypeInfo ( ) . IsValueType ? Activator . CreateInstance ( type ) :
57
+ return type . GetTypeInfo ( ) . IsValueType ? Activator . CreateInstance ( type ) :
57
58
null ;
58
59
}
59
60
@@ -68,34 +69,8 @@ public virtual object ConvertTo([NotNull] Type type, CultureInfo culture)
68
69
69
70
public static bool CanConvertFromString ( Type destinationType )
70
71
{
71
- return GetConverterDelegate ( destinationType ) != null ;
72
- }
73
-
74
- private object ConvertSimpleType ( CultureInfo culture , object value , Type destinationType )
75
- {
76
- if ( value == null || value . GetType ( ) . IsAssignableFrom ( destinationType ) )
77
- {
78
- return value ;
79
- }
80
-
81
- // In case of a Nullable object, we try again with its underlying type.
82
- destinationType = UnwrapNullableType ( destinationType ) ;
83
-
84
- // if this is a user-input value but the user didn't type anything, return no value
85
- var valueAsString = value as string ;
86
- if ( valueAsString != null && string . IsNullOrWhiteSpace ( valueAsString ) )
87
- {
88
- return null ;
89
- }
90
-
91
- var converter = GetConverterDelegate ( destinationType ) ;
92
- if ( converter == null )
93
- {
94
- var message = Resources . FormatValueProviderResult_NoConverterExists ( value . GetType ( ) , destinationType ) ;
95
- throw new InvalidOperationException ( message ) ;
96
- }
97
-
98
- return converter ( value , culture ) ;
72
+ return TypeHelper . IsSimpleType ( UnwrapNullableType ( destinationType ) ) ||
73
+ TypeHelper . HasStringConverter ( destinationType ) ;
99
74
}
100
75
101
76
private object UnwrapPossibleArrayType ( CultureInfo culture , object value , Type destinationType )
@@ -144,121 +119,57 @@ private object UnwrapPossibleArrayType(CultureInfo culture, object value, Type d
144
119
return ConvertSimpleType ( culture , value , destinationType ) ;
145
120
}
146
121
147
- private static Func < object , CultureInfo , object > GetConverterDelegate ( Type destinationType )
122
+ private object ConvertSimpleType ( CultureInfo culture , object value , Type destinationType )
148
123
{
149
- destinationType = UnwrapNullableType ( destinationType ) ;
150
-
151
- if ( destinationType == typeof ( string ) )
152
- {
153
- return ( value , culture ) => Convert . ToString ( value , culture ) ;
154
- }
155
-
156
- if ( destinationType == typeof ( int ) )
157
- {
158
- return ( value , culture ) => Convert . ToInt32 ( value , culture ) ;
159
- }
160
-
161
- if ( destinationType == typeof ( long ) )
162
- {
163
- return ( value , culture ) => Convert . ToInt64 ( value , culture ) ;
164
- }
165
-
166
- if ( destinationType == typeof ( float ) )
124
+ if ( value == null || value . GetType ( ) . IsAssignableFrom ( destinationType ) )
167
125
{
168
- return ( value , culture ) => Convert . ToSingle ( value , culture ) ;
126
+ return value ;
169
127
}
170
128
171
- if ( destinationType == typeof ( double ) )
172
- {
173
- return ( value , culture ) => Convert . ToDouble ( value , culture ) ;
174
- }
129
+ // In case of a Nullable object, we try again with its underlying type.
130
+ destinationType = UnwrapNullableType ( destinationType ) ;
175
131
176
- if ( destinationType == typeof ( decimal ) )
132
+ // if this is a user-input value but the user didn't type anything, return no value
133
+ var valueAsString = value as string ;
134
+ if ( valueAsString != null && string . IsNullOrWhiteSpace ( valueAsString ) )
177
135
{
178
- return ( value , culture ) => Convert . ToDecimal ( value , culture ) ;
136
+ return null ;
179
137
}
180
138
181
- if ( destinationType == typeof ( bool ) )
139
+ var converter = TypeDescriptor . GetConverter ( destinationType ) ;
140
+ var canConvertFrom = converter . CanConvertFrom ( value . GetType ( ) ) ;
141
+ if ( ! canConvertFrom )
182
142
{
183
- return ( value , culture ) => Convert . ToBoolean ( value , culture ) ;
143
+ converter = TypeDescriptor . GetConverter ( value . GetType ( ) ) ;
184
144
}
185
-
186
- if ( destinationType == typeof ( DateTime ) )
145
+ if ( ! ( canConvertFrom || converter . CanConvertTo ( destinationType ) ) )
187
146
{
188
- return ( value , culture ) =>
147
+ // EnumConverter cannot convert integer, so we verify manually
148
+ if ( destinationType . IsEnum ( ) && ( value is int ) )
189
149
{
190
- ThrowIfNotStringType ( value , destinationType ) ;
191
- return DateTime . Parse ( ( string ) value , culture ) ;
192
- } ;
193
- }
150
+ return Enum . ToObject ( destinationType , ( int ) value ) ;
151
+ }
194
152
195
- if ( destinationType == typeof ( DateTimeOffset ) )
196
- {
197
- return ( value , culture ) =>
198
- {
199
- ThrowIfNotStringType ( value , destinationType ) ;
200
- return DateTimeOffset . Parse ( ( string ) value , culture ) ;
201
- } ;
153
+ throw new InvalidOperationException (
154
+ Resources . FormatValueProviderResult_NoConverterExists ( value . GetType ( ) , destinationType ) ) ;
202
155
}
203
156
204
- if ( destinationType == typeof ( TimeSpan ) )
157
+ try
205
158
{
206
- return ( value , culture ) =>
207
- {
208
- ThrowIfNotStringType ( value , destinationType ) ;
209
- return TimeSpan . Parse ( ( string ) value , culture ) ;
210
- } ;
159
+ return canConvertFrom
160
+ ? converter . ConvertFrom ( null , culture , value )
161
+ : converter . ConvertTo ( null , culture , value , destinationType ) ;
211
162
}
212
-
213
- if ( destinationType == typeof ( Guid ) )
163
+ catch ( Exception ex )
214
164
{
215
- return ( value , culture ) =>
216
- {
217
- ThrowIfNotStringType ( value , destinationType ) ;
218
- return Guid . Parse ( ( string ) value ) ;
219
- } ;
220
- }
221
-
222
- if ( destinationType . GetTypeInfo ( ) . IsEnum )
223
- {
224
- return ( value , culture ) =>
225
- {
226
- // EnumConverter cannot convert integer, so we verify manually
227
- if ( ( value is int ) )
228
- {
229
- if ( Enum . IsDefined ( destinationType , value ) )
230
- {
231
- return Enum . ToObject ( destinationType , ( int ) value ) ;
232
- }
233
-
234
- throw new FormatException (
235
- Resources . FormatValueProviderResult_CannotConvertEnum ( value ,
236
- destinationType ) ) ;
237
- }
238
- else
239
- {
240
- ThrowIfNotStringType ( value , destinationType ) ;
241
- return Enum . Parse ( destinationType , ( string ) value ) ;
242
- }
243
- } ;
165
+ throw new InvalidOperationException (
166
+ Resources . FormatValueProviderResult_ConversionThrew ( value . GetType ( ) , destinationType ) , ex ) ;
244
167
}
245
-
246
- return null ;
247
168
}
248
169
249
170
private static Type UnwrapNullableType ( Type destinationType )
250
171
{
251
172
return Nullable . GetUnderlyingType ( destinationType ) ?? destinationType ;
252
173
}
253
-
254
- private static void ThrowIfNotStringType ( object value , Type destinationType )
255
- {
256
- var type = value . GetType ( ) ;
257
- if ( type != typeof ( string ) )
258
- {
259
- var message = Resources . FormatValueProviderResult_NoConverterExists ( type , destinationType ) ;
260
- throw new InvalidOperationException ( message ) ;
261
- }
262
- }
263
174
}
264
175
}
0 commit comments