PageRenderTime 58ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/monotouch/Newtonsoft.Json/Utilities/ConvertUtils.cs

https://github.com/Sfyler/c-sharp
C# | 515 lines | 310 code | 71 blank | 134 comment | 115 complexity | 83e565f1239b5ab433b8df054bf886fc MD5 | raw file
Possible License(s): BSD-3-Clause
  1. #region License
  2. // Copyright (c) 2007 James Newton-King
  3. //
  4. // Permission is hereby granted, free of charge, to any person
  5. // obtaining a copy of this software and associated documentation
  6. // files (the "Software"), to deal in the Software without
  7. // restriction, including without limitation the rights to use,
  8. // copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. // copies of the Software, and to permit persons to whom the
  10. // Software is furnished to do so, subject to the following
  11. // conditions:
  12. //
  13. // The above copyright notice and this permission notice shall be
  14. // included in all copies or substantial portions of the Software.
  15. //
  16. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  17. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
  18. // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  19. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  20. // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  21. // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  22. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  23. // OTHER DEALINGS IN THE SOFTWARE.
  24. #endregion
  25. using System;
  26. using System.Collections.Generic;
  27. using System.Linq;
  28. using System.Text;
  29. using System.Globalization;
  30. using System.ComponentModel;
  31. using Newtonsoft.Json.Serialization;
  32. using System.Reflection;
  33. #if !(SILVERLIGHT || MONODROID || MONOTOUCH)
  34. using System.Data.SqlTypes;
  35. #endif
  36. namespace Newtonsoft.Json.Utilities
  37. {
  38. internal static class ConvertUtils
  39. {
  40. internal struct TypeConvertKey : IEquatable<TypeConvertKey>
  41. {
  42. private readonly Type _initialType;
  43. private readonly Type _targetType;
  44. public Type InitialType
  45. {
  46. get { return _initialType; }
  47. }
  48. public Type TargetType
  49. {
  50. get { return _targetType; }
  51. }
  52. public TypeConvertKey(Type initialType, Type targetType)
  53. {
  54. _initialType = initialType;
  55. _targetType = targetType;
  56. }
  57. public override int GetHashCode()
  58. {
  59. return _initialType.GetHashCode() ^ _targetType.GetHashCode();
  60. }
  61. public override bool Equals(object obj)
  62. {
  63. if (!(obj is TypeConvertKey))
  64. return false;
  65. return Equals((TypeConvertKey)obj);
  66. }
  67. public bool Equals(TypeConvertKey other)
  68. {
  69. return (_initialType == other._initialType && _targetType == other._targetType);
  70. }
  71. }
  72. private static readonly ThreadSafeStore<TypeConvertKey, Func<object, object>> CastConverters =
  73. new ThreadSafeStore<TypeConvertKey, Func<object, object>>(CreateCastConverter);
  74. private static Func<object, object> CreateCastConverter(TypeConvertKey t)
  75. {
  76. MethodInfo castMethodInfo = t.TargetType.GetMethod("op_Implicit", new[] { t.InitialType });
  77. if (castMethodInfo == null)
  78. castMethodInfo = t.TargetType.GetMethod("op_Explicit", new[] { t.InitialType });
  79. if (castMethodInfo == null)
  80. return null;
  81. MethodCall<object, object> call = JsonTypeReflector.ReflectionDelegateFactory.CreateMethodCall<object>(castMethodInfo);
  82. return o => call(null, o);
  83. }
  84. public static bool CanConvertType(Type initialType, Type targetType, bool allowTypeNameToString)
  85. {
  86. ValidationUtils.ArgumentNotNull(initialType, "initialType");
  87. ValidationUtils.ArgumentNotNull(targetType, "targetType");
  88. if (ReflectionUtils.IsNullableType(targetType))
  89. targetType = Nullable.GetUnderlyingType(targetType);
  90. if (targetType == initialType)
  91. return true;
  92. if (typeof(IConvertible).IsAssignableFrom(initialType) && typeof(IConvertible).IsAssignableFrom(targetType))
  93. {
  94. return true;
  95. }
  96. #if !PocketPC && !NET20
  97. if (initialType == typeof(DateTime) && targetType == typeof(DateTimeOffset))
  98. return true;
  99. #endif
  100. if (initialType == typeof(Guid) && (targetType == typeof(Guid) || targetType == typeof(string)))
  101. return true;
  102. if (initialType == typeof(Type) && targetType == typeof(string))
  103. return true;
  104. #if !PocketPC
  105. // see if source or target types have a TypeConverter that converts between the two
  106. TypeConverter toConverter = GetConverter(initialType);
  107. if (toConverter != null && !IsComponentConverter(toConverter) && toConverter.CanConvertTo(targetType))
  108. {
  109. if (allowTypeNameToString || toConverter.GetType() != typeof(TypeConverter))
  110. return true;
  111. }
  112. TypeConverter fromConverter = GetConverter(targetType);
  113. if (fromConverter != null && !IsComponentConverter(fromConverter) && fromConverter.CanConvertFrom(initialType))
  114. return true;
  115. #endif
  116. // handle DBNull and INullable
  117. if (initialType == typeof(DBNull))
  118. {
  119. if (ReflectionUtils.IsNullable(targetType))
  120. return true;
  121. }
  122. return false;
  123. }
  124. private static bool IsComponentConverter(TypeConverter converter)
  125. {
  126. #if !SILVERLIGHT && !PocketPC
  127. return (converter is ComponentConverter);
  128. #else
  129. return false;
  130. #endif
  131. }
  132. #region Convert
  133. /// <summary>
  134. /// Converts the value to the specified type.
  135. /// </summary>
  136. /// <typeparam name="T">The type to convert the value to.</typeparam>
  137. /// <param name="initialValue">The value to convert.</param>
  138. /// <returns>The converted type.</returns>
  139. public static T Convert<T>(object initialValue)
  140. {
  141. return Convert<T>(initialValue, CultureInfo.CurrentCulture);
  142. }
  143. /// <summary>
  144. /// Converts the value to the specified type.
  145. /// </summary>
  146. /// <typeparam name="T">The type to convert the value to.</typeparam>
  147. /// <param name="initialValue">The value to convert.</param>
  148. /// <param name="culture">The culture to use when converting.</param>
  149. /// <returns>The converted type.</returns>
  150. public static T Convert<T>(object initialValue, CultureInfo culture)
  151. {
  152. return (T)Convert(initialValue, culture, typeof(T));
  153. }
  154. /// <summary>
  155. /// Converts the value to the specified type.
  156. /// </summary>
  157. /// <param name="initialValue">The value to convert.</param>
  158. /// <param name="culture">The culture to use when converting.</param>
  159. /// <param name="targetType">The type to convert the value to.</param>
  160. /// <returns>The converted type.</returns>
  161. public static object Convert(object initialValue, CultureInfo culture, Type targetType)
  162. {
  163. if (initialValue == null)
  164. throw new ArgumentNullException("initialValue");
  165. if (ReflectionUtils.IsNullableType(targetType))
  166. targetType = Nullable.GetUnderlyingType(targetType);
  167. Type initialType = initialValue.GetType();
  168. if (targetType == initialType)
  169. return initialValue;
  170. if (initialValue is string && typeof(Type).IsAssignableFrom(targetType))
  171. return Type.GetType((string) initialValue, true);
  172. if (targetType.IsInterface || targetType.IsGenericTypeDefinition || targetType.IsAbstract)
  173. throw new ArgumentException("Target type {0} is not a value type or a non-abstract class.".FormatWith(CultureInfo.InvariantCulture, targetType), "targetType");
  174. // use Convert.ChangeType if both types are IConvertible
  175. if (initialValue is IConvertible && typeof(IConvertible).IsAssignableFrom(targetType))
  176. {
  177. if (targetType.IsEnum)
  178. {
  179. if (initialValue is string)
  180. return Enum.Parse(targetType, initialValue.ToString(), true);
  181. else if (IsInteger(initialValue))
  182. return Enum.ToObject(targetType, initialValue);
  183. }
  184. return System.Convert.ChangeType(initialValue, targetType, culture);
  185. }
  186. #if !PocketPC && !NET20
  187. if (initialValue is DateTime && targetType == typeof(DateTimeOffset))
  188. return new DateTimeOffset((DateTime)initialValue);
  189. #endif
  190. if (initialValue is string)
  191. {
  192. if (targetType == typeof (Guid))
  193. return new Guid((string) initialValue);
  194. if (targetType == typeof (Uri))
  195. return new Uri((string) initialValue);
  196. if (targetType == typeof (TimeSpan))
  197. #if !(NET35 || NET20 || SILVERLIGHT)
  198. return TimeSpan.Parse((string) initialValue, CultureInfo.InvariantCulture);
  199. #else
  200. return TimeSpan.Parse((string)initialValue);
  201. #endif
  202. }
  203. #if !PocketPC
  204. // see if source or target types have a TypeConverter that converts between the two
  205. TypeConverter toConverter = GetConverter(initialType);
  206. if (toConverter != null && toConverter.CanConvertTo(targetType))
  207. {
  208. #if !SILVERLIGHT
  209. return toConverter.ConvertTo(null, culture, initialValue, targetType);
  210. #else
  211. return toConverter.ConvertTo(initialValue, targetType);
  212. #endif
  213. }
  214. TypeConverter fromConverter = GetConverter(targetType);
  215. if (fromConverter != null && fromConverter.CanConvertFrom(initialType))
  216. {
  217. #if !SILVERLIGHT
  218. return fromConverter.ConvertFrom(null, culture, initialValue);
  219. #else
  220. return fromConverter.ConvertFrom(initialValue);
  221. #endif
  222. }
  223. #endif
  224. // handle DBNull and INullable
  225. if (initialValue == DBNull.Value)
  226. {
  227. if (ReflectionUtils.IsNullable(targetType))
  228. return EnsureTypeAssignable(null, initialType, targetType);
  229. throw new Exception("Can not convert null {0} into non-nullable {1}.".FormatWith(CultureInfo.InvariantCulture, initialType, targetType));
  230. }
  231. #if !(SILVERLIGHT || MONODROID || MONOTOUCH)
  232. if (initialValue is INullable)
  233. return EnsureTypeAssignable(ToValue((INullable)initialValue), initialType, targetType);
  234. #endif
  235. throw new Exception("Can not convert from {0} to {1}.".FormatWith(CultureInfo.InvariantCulture, initialType, targetType));
  236. }
  237. #endregion
  238. #region TryConvert
  239. /// <summary>
  240. /// Converts the value to the specified type.
  241. /// </summary>
  242. /// <typeparam name="T">The type to convert the value to.</typeparam>
  243. /// <param name="initialValue">The value to convert.</param>
  244. /// <param name="convertedValue">The converted value if the conversion was successful or the default value of <c>T</c> if it failed.</param>
  245. /// <returns>
  246. /// <c>true</c> if <c>initialValue</c> was converted successfully; otherwise, <c>false</c>.
  247. /// </returns>
  248. public static bool TryConvert<T>(object initialValue, out T convertedValue)
  249. {
  250. return TryConvert(initialValue, CultureInfo.CurrentCulture, out convertedValue);
  251. }
  252. /// <summary>
  253. /// Converts the value to the specified type.
  254. /// </summary>
  255. /// <typeparam name="T">The type to convert the value to.</typeparam>
  256. /// <param name="initialValue">The value to convert.</param>
  257. /// <param name="culture">The culture to use when converting.</param>
  258. /// <param name="convertedValue">The converted value if the conversion was successful or the default value of <c>T</c> if it failed.</param>
  259. /// <returns>
  260. /// <c>true</c> if <c>initialValue</c> was converted successfully; otherwise, <c>false</c>.
  261. /// </returns>
  262. public static bool TryConvert<T>(object initialValue, CultureInfo culture, out T convertedValue)
  263. {
  264. return MiscellaneousUtils.TryAction<T>(delegate
  265. {
  266. object tempConvertedValue;
  267. TryConvert(initialValue, CultureInfo.CurrentCulture, typeof(T), out tempConvertedValue);
  268. return (T)tempConvertedValue;
  269. }, out convertedValue);
  270. }
  271. /// <summary>
  272. /// Converts the value to the specified type.
  273. /// </summary>
  274. /// <param name="initialValue">The value to convert.</param>
  275. /// <param name="culture">The culture to use when converting.</param>
  276. /// <param name="targetType">The type to convert the value to.</param>
  277. /// <param name="convertedValue">The converted value if the conversion was successful or the default value of <c>T</c> if it failed.</param>
  278. /// <returns>
  279. /// <c>true</c> if <c>initialValue</c> was converted successfully; otherwise, <c>false</c>.
  280. /// </returns>
  281. public static bool TryConvert(object initialValue, CultureInfo culture, Type targetType, out object convertedValue)
  282. {
  283. return MiscellaneousUtils.TryAction<object>(delegate { return Convert(initialValue, culture, targetType); }, out convertedValue);
  284. }
  285. #endregion
  286. #region ConvertOrCast
  287. /// <summary>
  288. /// Converts the value to the specified type. If the value is unable to be converted, the
  289. /// value is checked whether it assignable to the specified type.
  290. /// </summary>
  291. /// <typeparam name="T">The type to convert or cast the value to.</typeparam>
  292. /// <param name="initialValue">The value to convert.</param>
  293. /// <returns>The converted type. If conversion was unsuccessful, the initial value is returned if assignable to the target type</returns>
  294. public static T ConvertOrCast<T>(object initialValue)
  295. {
  296. return ConvertOrCast<T>(initialValue, CultureInfo.CurrentCulture);
  297. }
  298. /// <summary>
  299. /// Converts the value to the specified type. If the value is unable to be converted, the
  300. /// value is checked whether it assignable to the specified type.
  301. /// </summary>
  302. /// <typeparam name="T">The type to convert or cast the value to.</typeparam>
  303. /// <param name="initialValue">The value to convert.</param>
  304. /// <param name="culture">The culture to use when converting.</param>
  305. /// <returns>The converted type. If conversion was unsuccessful, the initial value is returned if assignable to the target type</returns>
  306. public static T ConvertOrCast<T>(object initialValue, CultureInfo culture)
  307. {
  308. return (T)ConvertOrCast(initialValue, culture, typeof(T));
  309. }
  310. /// <summary>
  311. /// Converts the value to the specified type. If the value is unable to be converted, the
  312. /// value is checked whether it assignable to the specified type.
  313. /// </summary>
  314. /// <param name="initialValue">The value to convert.</param>
  315. /// <param name="culture">The culture to use when converting.</param>
  316. /// <param name="targetType">The type to convert or cast the value to.</param>
  317. /// <returns>
  318. /// The converted type. If conversion was unsuccessful, the initial value
  319. /// is returned if assignable to the target type.
  320. /// </returns>
  321. public static object ConvertOrCast(object initialValue, CultureInfo culture, Type targetType)
  322. {
  323. object convertedValue;
  324. if (targetType == typeof(object))
  325. return initialValue;
  326. if (initialValue == null && ReflectionUtils.IsNullable(targetType))
  327. return null;
  328. if (TryConvert(initialValue, culture, targetType, out convertedValue))
  329. return convertedValue;
  330. return EnsureTypeAssignable(initialValue, ReflectionUtils.GetObjectType(initialValue), targetType);
  331. }
  332. #endregion
  333. #region TryConvertOrCast
  334. /// <summary>
  335. /// Converts the value to the specified type. If the value is unable to be converted, the
  336. /// value is checked whether it assignable to the specified type.
  337. /// </summary>
  338. /// <typeparam name="T">The type to convert the value to.</typeparam>
  339. /// <param name="initialValue">The value to convert.</param>
  340. /// <param name="convertedValue">The converted value if the conversion was successful or the default value of <c>T</c> if it failed.</param>
  341. /// <returns>
  342. /// <c>true</c> if <c>initialValue</c> was converted successfully or is assignable; otherwise, <c>false</c>.
  343. /// </returns>
  344. public static bool TryConvertOrCast<T>(object initialValue, out T convertedValue)
  345. {
  346. return TryConvertOrCast<T>(initialValue, CultureInfo.CurrentCulture, out convertedValue);
  347. }
  348. /// <summary>
  349. /// Converts the value to the specified type. If the value is unable to be converted, the
  350. /// value is checked whether it assignable to the specified type.
  351. /// </summary>
  352. /// <typeparam name="T">The type to convert the value to.</typeparam>
  353. /// <param name="initialValue">The value to convert.</param>
  354. /// <param name="culture">The culture to use when converting.</param>
  355. /// <param name="convertedValue">The converted value if the conversion was successful or the default value of <c>T</c> if it failed.</param>
  356. /// <returns>
  357. /// <c>true</c> if <c>initialValue</c> was converted successfully or is assignable; otherwise, <c>false</c>.
  358. /// </returns>
  359. public static bool TryConvertOrCast<T>(object initialValue, CultureInfo culture, out T convertedValue)
  360. {
  361. return MiscellaneousUtils.TryAction<T>(delegate
  362. {
  363. object tempConvertedValue;
  364. TryConvertOrCast(initialValue, CultureInfo.CurrentCulture, typeof(T), out tempConvertedValue);
  365. return (T)tempConvertedValue;
  366. }, out convertedValue);
  367. }
  368. /// <summary>
  369. /// Converts the value to the specified type. If the value is unable to be converted, the
  370. /// value is checked whether it assignable to the specified type.
  371. /// </summary>
  372. /// <param name="initialValue">The value to convert.</param>
  373. /// <param name="culture">The culture to use when converting.</param>
  374. /// <param name="targetType">The type to convert the value to.</param>
  375. /// <param name="convertedValue">The converted value if the conversion was successful or the default value of <c>T</c> if it failed.</param>
  376. /// <returns>
  377. /// <c>true</c> if <c>initialValue</c> was converted successfully or is assignable; otherwise, <c>false</c>.
  378. /// </returns>
  379. public static bool TryConvertOrCast(object initialValue, CultureInfo culture, Type targetType, out object convertedValue)
  380. {
  381. return MiscellaneousUtils.TryAction<object>(delegate { return ConvertOrCast(initialValue, culture, targetType); }, out convertedValue);
  382. }
  383. #endregion
  384. private static object EnsureTypeAssignable(object value, Type initialType, Type targetType)
  385. {
  386. Type valueType = (value != null) ? value.GetType() : null;
  387. if (value != null)
  388. {
  389. if (targetType.IsAssignableFrom(valueType))
  390. return value;
  391. Func<object, object> castConverter = CastConverters.Get(new TypeConvertKey(valueType, targetType));
  392. if (castConverter != null)
  393. return castConverter(value);
  394. }
  395. else
  396. {
  397. if (ReflectionUtils.IsNullable(targetType))
  398. return null;
  399. }
  400. throw new Exception("Could not cast or convert from {0} to {1}.".FormatWith(CultureInfo.InvariantCulture, (initialType != null) ? initialType.ToString() : "{null}", targetType));
  401. }
  402. #if !(SILVERLIGHT || MONODROID || MONOTOUCH)
  403. public static object ToValue(INullable nullableValue)
  404. {
  405. if (nullableValue == null)
  406. return null;
  407. else if (nullableValue is SqlInt32)
  408. return ToValue((SqlInt32)nullableValue);
  409. else if (nullableValue is SqlInt64)
  410. return ToValue((SqlInt64)nullableValue);
  411. else if (nullableValue is SqlBoolean)
  412. return ToValue((SqlBoolean)nullableValue);
  413. else if (nullableValue is SqlString)
  414. return ToValue((SqlString)nullableValue);
  415. else if (nullableValue is SqlDateTime)
  416. return ToValue((SqlDateTime)nullableValue);
  417. throw new Exception("Unsupported INullable type: {0}".FormatWith(CultureInfo.InvariantCulture, nullableValue.GetType()));
  418. }
  419. #endif
  420. #if !PocketPC
  421. internal static TypeConverter GetConverter(Type t)
  422. {
  423. return JsonTypeReflector.GetTypeConverter(t);
  424. }
  425. #endif
  426. public static bool IsInteger(object value)
  427. {
  428. switch (System.Convert.GetTypeCode(value))
  429. {
  430. case TypeCode.SByte:
  431. case TypeCode.Byte:
  432. case TypeCode.Int16:
  433. case TypeCode.UInt16:
  434. case TypeCode.Int32:
  435. case TypeCode.UInt32:
  436. case TypeCode.Int64:
  437. case TypeCode.UInt64:
  438. return true;
  439. default:
  440. return false;
  441. }
  442. }
  443. }
  444. }