IConvertibleExtensions.cs 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. using System;
  2. using System.ComponentModel;
  3. using System.Globalization;
  4. namespace Masuit.Tools;
  5. public static class IConvertibleExtensions
  6. {
  7. public static bool IsNumeric(this Type type)
  8. {
  9. switch (Type.GetTypeCode(type))
  10. {
  11. case TypeCode.Byte:
  12. case TypeCode.SByte:
  13. case TypeCode.UInt16:
  14. case TypeCode.UInt32:
  15. case TypeCode.UInt64:
  16. case TypeCode.Int16:
  17. case TypeCode.Int32:
  18. case TypeCode.Int64:
  19. case TypeCode.Decimal:
  20. case TypeCode.Double:
  21. case TypeCode.Single:
  22. return true;
  23. default:
  24. return false;
  25. }
  26. }
  27. /// <summary>
  28. /// 类型直转
  29. /// </summary>
  30. /// <typeparam name="T"></typeparam>
  31. /// <param name="value"></param>
  32. /// <returns></returns>
  33. public static T ConvertTo<T>(this IConvertible value) where T : IConvertible
  34. {
  35. if (value != null)
  36. {
  37. var type = typeof(T);
  38. if (value.GetType() == type)
  39. {
  40. return (T)value;
  41. }
  42. if (type.IsEnum)
  43. {
  44. return (T)Enum.Parse(type, value.ToString(CultureInfo.InvariantCulture));
  45. }
  46. if (value == DBNull.Value)
  47. {
  48. return default;
  49. }
  50. if (type.IsNumeric())
  51. {
  52. return (T)value.ToType(type, new NumberFormatInfo());
  53. }
  54. if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
  55. {
  56. var underlyingType = Nullable.GetUnderlyingType(type);
  57. return (T)(underlyingType!.IsEnum ? Enum.Parse(underlyingType, value.ToString(CultureInfo.CurrentCulture)) : Convert.ChangeType(value, underlyingType));
  58. }
  59. var converter = TypeDescriptor.GetConverter(value);
  60. if (converter.CanConvertTo(type))
  61. {
  62. return (T)converter.ConvertTo(value, type);
  63. }
  64. converter = TypeDescriptor.GetConverter(type);
  65. if (converter.CanConvertFrom(value.GetType()))
  66. {
  67. return (T)converter.ConvertFrom(value);
  68. }
  69. return (T)Convert.ChangeType(value, type);
  70. }
  71. return (T)value;
  72. }
  73. /// <summary>
  74. /// 类型直转
  75. /// </summary>
  76. /// <typeparam name="T"></typeparam>
  77. /// <param name="value"></param>
  78. /// <param name="defaultValue">转换失败的默认值</param>
  79. /// <returns></returns>
  80. public static T TryConvertTo<T>(this IConvertible value, T defaultValue = default) where T : IConvertible
  81. {
  82. try
  83. {
  84. return ConvertTo<T>(value);
  85. }
  86. catch
  87. {
  88. return defaultValue;
  89. }
  90. }
  91. /// <summary>
  92. /// 类型直转
  93. /// </summary>
  94. /// <typeparam name="T"></typeparam>
  95. /// <param name="value"></param>
  96. /// <param name="result">转换失败的默认值</param>
  97. /// <returns></returns>
  98. public static bool TryConvertTo<T>(this IConvertible value, out T result) where T : IConvertible
  99. {
  100. try
  101. {
  102. result = ConvertTo<T>(value);
  103. return true;
  104. }
  105. catch
  106. {
  107. result = default;
  108. return false;
  109. }
  110. }
  111. /// <summary>
  112. /// 类型直转
  113. /// </summary>
  114. /// <param name="value"></param>
  115. /// <param name="type">目标类型</param>
  116. /// <param name="result">转换失败的默认值</param>
  117. /// <returns></returns>
  118. public static bool TryConvertTo(this IConvertible value, Type type, out object result)
  119. {
  120. try
  121. {
  122. result = ConvertTo(value, type);
  123. return true;
  124. }
  125. catch
  126. {
  127. result = null;
  128. return false;
  129. }
  130. }
  131. /// <summary>
  132. /// 类型直转
  133. /// </summary>
  134. /// <param name="value"></param>
  135. /// <param name="type">目标类型</param>
  136. /// <returns></returns>
  137. public static object ConvertTo(this IConvertible value, Type type)
  138. {
  139. if (value == null)
  140. {
  141. return null;
  142. }
  143. if (value.GetType() == type)
  144. {
  145. return value;
  146. }
  147. if (value == DBNull.Value)
  148. {
  149. return null;
  150. }
  151. if (type.IsAssignableFrom(typeof(string)))
  152. {
  153. return value.ToString();
  154. }
  155. if (type.IsEnum)
  156. {
  157. return Enum.Parse(type, value.ToString(CultureInfo.InvariantCulture));
  158. }
  159. if (type.IsAssignableFrom(typeof(Guid)))
  160. {
  161. return Guid.Parse(value.ToString());
  162. }
  163. if (type.IsAssignableFrom(typeof(DateTime)))
  164. {
  165. return DateTime.Parse(value.ToString());
  166. }
  167. if (type.IsAssignableFrom(typeof(DateTimeOffset)))
  168. {
  169. return DateTimeOffset.Parse(value.ToString());
  170. }
  171. if (type.IsNumeric())
  172. {
  173. return value.ToType(type, new NumberFormatInfo());
  174. }
  175. if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
  176. {
  177. var underlyingType = Nullable.GetUnderlyingType(type);
  178. return underlyingType!.IsEnum ? Enum.Parse(underlyingType, value.ToString(CultureInfo.CurrentCulture)) : Convert.ChangeType(value, underlyingType);
  179. }
  180. var converter = TypeDescriptor.GetConverter(value);
  181. if (converter.CanConvertTo(type))
  182. {
  183. return converter.ConvertTo(value, type);
  184. }
  185. converter = TypeDescriptor.GetConverter(type);
  186. return converter.CanConvertFrom(value.GetType()) ? converter.ConvertFrom(value) : Convert.ChangeType(value, type);
  187. }
  188. /// <summary>
  189. /// 对象类型转换
  190. /// </summary>
  191. /// <param name="this">当前值</param>
  192. /// <returns>转换后的对象</returns>
  193. public static T ChangeTypeTo<T>(this object @this)
  194. {
  195. return (T)ChangeType(@this, typeof(T));
  196. }
  197. /// <summary>
  198. /// 对象类型转换
  199. /// </summary>
  200. /// <param name="this">当前值</param>
  201. /// <param name="defaultValue">默认值</param>
  202. /// <returns>转换后的对象</returns>
  203. public static T ChangeTypeTo<T>(this object @this, T defaultValue)
  204. {
  205. return @this == null ? defaultValue : (T)ChangeType(@this, typeof(T));
  206. }
  207. /// <summary>
  208. /// 对象类型转换
  209. /// </summary>
  210. /// <param name="this">当前值</param>
  211. /// <param name="type">指定类型的类型</param>
  212. /// <returns>转换后的对象</returns>
  213. public static object ChangeType(this object @this, Type type)
  214. {
  215. var currType = Nullable.GetUnderlyingType(@this.GetType()) ?? @this.GetType();
  216. type = Nullable.GetUnderlyingType(type) ?? type;
  217. if (@this == DBNull.Value)
  218. {
  219. if (!type.IsValueType)
  220. {
  221. return null;
  222. }
  223. throw new Exception("不能将null值转换为" + type.Name + "类型!");
  224. }
  225. if (currType == type)
  226. {
  227. return @this;
  228. }
  229. if (type.IsAssignableFrom(typeof(string)))
  230. {
  231. return @this.ToString();
  232. }
  233. if (type.IsEnum)
  234. {
  235. return Enum.Parse(type, @this.ToString(), true);
  236. }
  237. if (type.IsAssignableFrom(typeof(Guid)))
  238. {
  239. return Guid.Parse(@this.ToString());
  240. }
  241. if (!type.IsArray || !currType.IsArray)
  242. {
  243. return Convert.ChangeType(@this, type);
  244. }
  245. var length = ((Array)@this).Length;
  246. var targetType = Type.GetType(type.FullName.Trim('[', ']'));
  247. var array = Array.CreateInstance(targetType, length);
  248. for (int j = 0; j < length; j++)
  249. {
  250. var tmp = ((Array)@this).GetValue(j);
  251. array.SetValue(ChangeType(tmp, targetType), j);
  252. }
  253. return array;
  254. }
  255. }