TypeExtension.cs 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460
  1. using SqlSugar;
  2. using System.Collections.Concurrent;
  3. using System.ComponentModel;
  4. using System.Data;
  5. using System.Globalization;
  6. using System.Numerics;
  7. using System.Reflection;
  8. using System.Security.Cryptography;
  9. using System.Text;
  10. namespace ServiceCenter.Extensions
  11. {
  12. /// <summary>
  13. /// 类型转换扩展
  14. /// </summary>
  15. public static class TypeExtension
  16. {
  17. /// <summary>
  18. /// 将字符串转换为short
  19. /// </summary>
  20. /// <param name="value">需要转换的字符串</param>
  21. /// <returns></returns>
  22. public static short ToShort(this string value)
  23. {
  24. return Convert.ToInt16(value);
  25. }
  26. /// <summary>
  27. /// 将int转换为short
  28. /// </summary>
  29. /// <param name="value">需要转换的字符串</param>
  30. /// <returns></returns>
  31. public static short ToShort(this int value)
  32. {
  33. return Convert.ToInt16(value);
  34. }
  35. /// <summary>
  36. /// 将decimal转换为short
  37. /// </summary>
  38. /// <param name="value">需要转换的字符串</param>
  39. /// <returns></returns>
  40. public static short ToShort(this decimal value)
  41. {
  42. return Convert.ToInt16(value);
  43. }
  44. /// <summary>
  45. /// 将字符串转换为int
  46. /// </summary>
  47. /// <param name="value">需要转换的字符串</param>
  48. /// <returns></returns>
  49. public static int ToInt(this string value)
  50. {
  51. return Convert.ToInt32(value);
  52. }
  53. /// <summary>
  54. /// 判断值为奇数/偶数
  55. /// </summary>
  56. /// <param name="value">需要判断的值</param>
  57. /// <returns> true:是奇数 false:是偶数</returns>
  58. public static bool OddNumberOrEven(this short value)
  59. {
  60. return value % 2 != 0;
  61. }
  62. /// <summary>
  63. /// 获取short类型Code,只限设备组
  64. /// </summary>
  65. /// <param name="value"></param>
  66. /// <returns></returns>
  67. public static short GetShortCode(this string value)
  68. {
  69. return value.Replace("G", "").ToShort();
  70. }
  71. /// <summary>
  72. /// 数据映射
  73. /// </summary>
  74. /// <typeparam name="D"></typeparam>
  75. /// <typeparam name="S"></typeparam>
  76. /// <param name="s"></param>
  77. /// <returns></returns>
  78. public static D Mapper<D, S>(S s)
  79. {
  80. var d = Activator.CreateInstance<D>();
  81. var sType = s?.GetType();
  82. var dType = typeof(D);
  83. foreach (var sP in sType.GetProperties())
  84. {
  85. foreach (var dP in dType.GetProperties())
  86. {
  87. if (dP.Name == sP.Name)
  88. {
  89. dP.SetValue(d, sP.GetValue(s));
  90. break;
  91. }
  92. }
  93. }
  94. return d;
  95. }
  96. /// <summary>
  97. /// 获取字典
  98. /// </summary>
  99. /// <typeparam name="T1"></typeparam>
  100. /// <typeparam name="T2"></typeparam>
  101. /// <typeparam name="T3"></typeparam>
  102. /// <param name="t3"></param>
  103. /// <returns></returns>
  104. public static Dictionary<string, object> EntityClassToDictionary<T>(T t)
  105. {
  106. var type = typeof(SugarColumn);
  107. Dictionary<string, object> d = new Dictionary<string, object>();
  108. var sType = t.GetType();
  109. foreach (var sP in sType.GetProperties())
  110. {
  111. if (sP.CustomAttributes.Any(v => v.AttributeType == type) && sP.Name != "VER" && sP.Name != "ID")
  112. {
  113. d.Add(sP.Name, sP.GetValue(t));
  114. }
  115. }
  116. return d;
  117. }
  118. /// <summary>
  119. /// 获取MD5字符串
  120. /// </summary>
  121. /// <param name="myString"></param>
  122. /// <returns></returns>
  123. public static string GetMD5(this string myString)
  124. {
  125. var md5 = MD5.Create();
  126. var fromData = Encoding.Unicode.GetBytes(myString);
  127. var targetData = md5.ComputeHash(fromData);
  128. string byte2String = null;
  129. for (var i = 0; i < targetData.Length; i++)
  130. {
  131. byte2String += targetData[i].ToString("x");
  132. }
  133. return byte2String;
  134. }
  135. /// <summary>
  136. /// DataTable转换成实体类
  137. /// </summary>
  138. /// <typeparam name="T"></typeparam>
  139. /// <param name="dt"></param>
  140. /// <returns></returns>
  141. public static List<object> TableToEntity(this DataTable dt, string typeName)
  142. {
  143. var list = new List<object>();
  144. try
  145. {
  146. foreach (DataRow row in dt.Rows)
  147. {
  148. var entity = Type.GetType(typeName);
  149. PropertyInfo[] pArray = entity.GetType().GetProperties();
  150. foreach (var p in pArray)
  151. {
  152. if (dt.Columns.Contains(p.Name))
  153. {
  154. if (!p.CanWrite) continue;
  155. var value = row[p.Name];
  156. if (value != DBNull.Value)
  157. {
  158. var targetType = p.PropertyType;
  159. var convertType = targetType;
  160. if (targetType.IsGenericType && targetType.GetGenericTypeDefinition().Equals(typeof(Nullable<>)))
  161. {
  162. //可空类型
  163. var nullableConverter = new NullableConverter(targetType);
  164. convertType = nullableConverter.UnderlyingType;
  165. }
  166. if (!string.IsNullOrEmpty(convertType.FullName) && !string.IsNullOrEmpty(value.ToString()))
  167. {
  168. value = Convert.ChangeType(value, convertType);
  169. }
  170. switch (convertType.FullName)
  171. {
  172. case "System.Decimal":
  173. p.SetValue(entity, Convert.ToDecimal(value), null);
  174. break;
  175. case "System.String":
  176. p.SetValue(entity, Convert.ToString(value), null);
  177. break;
  178. case "System.Int32":
  179. p.SetValue(entity, Convert.ToInt32(value), null);
  180. break;
  181. case "System.Int64":
  182. p.SetValue(entity, Convert.ToInt64(value), null);
  183. break;
  184. case "System.Int16":
  185. p.SetValue(entity, Convert.ToInt16(value), null);
  186. break;
  187. case "System.Double":
  188. p.SetValue(entity, Convert.ToDouble(value), null);
  189. break;
  190. case "System.Single":
  191. p.SetValue(entity, Convert.ToSingle(value), null);
  192. break;
  193. case "System.DateTime":
  194. p.SetValue(entity, Convert.ToDateTime(value), null);
  195. break;
  196. default:
  197. p.SetValue(entity, value, null);
  198. break;
  199. }
  200. }
  201. }
  202. }
  203. list.Add(entity);
  204. }
  205. }
  206. catch (Exception ex)
  207. {
  208. }
  209. return list;
  210. }
  211. /// <summary>
  212. /// 转换到目标类型
  213. /// </summary>
  214. /// <param name="value"></param>
  215. /// <typeparam name="T"></typeparam>
  216. /// <returns></returns>
  217. internal static T ConvertTo<T>(this object value) => (T)typeof(T).FromObject(value);
  218. private static ConcurrentDictionary<Type, Func<string, object>> _dicFromObject = new ConcurrentDictionary<Type, Func<string, object>>();
  219. public static object FromObject(this Type targetType, object value, Encoding encoding = null)
  220. {
  221. if (targetType == typeof(object)) return value;
  222. if (encoding == null) encoding = Encoding.UTF8;
  223. var valueIsNull = value == null;
  224. var valueType = valueIsNull ? typeof(string) : value.GetType();
  225. if (valueType == targetType) return value;
  226. if (valueType == typeof(byte[])) //byte[] -> guid
  227. {
  228. if (targetType == typeof(Guid))
  229. {
  230. var bytes = value as byte[];
  231. return Guid.TryParse(BitConverter.ToString(bytes, 0, Math.Min(bytes.Length, 36)).Replace("-", ""), out var tryguid) ? tryguid : Guid.Empty;
  232. }
  233. if (targetType == typeof(Guid?))
  234. {
  235. var bytes = value as byte[];
  236. return Guid.TryParse(BitConverter.ToString(bytes, 0, Math.Min(bytes.Length, 36)).Replace("-", ""), out var tryguid) ? (Guid?)tryguid : null;
  237. }
  238. }
  239. if (targetType == typeof(byte[])) //guid -> byte[]
  240. {
  241. if (valueIsNull) return null;
  242. if (valueType == typeof(Guid) || valueType == typeof(Guid?))
  243. {
  244. var bytes = new byte[16];
  245. var guidN = ((Guid)value).ToString("N");
  246. for (var a = 0; a < guidN.Length; a += 2)
  247. bytes[a / 2] = byte.Parse($"{guidN[a]}{guidN[a + 1]}", NumberStyles.HexNumber);
  248. return bytes;
  249. }
  250. return encoding.GetBytes(value.ToInvariantCultureToString());
  251. }
  252. else if (targetType.IsArray)
  253. {
  254. if (value is Array valueArr)
  255. {
  256. var targetElementType = targetType.GetElementType();
  257. var sourceArrLen = valueArr.Length;
  258. var target = Array.CreateInstance(targetElementType, sourceArrLen);
  259. for (var a = 0; a < sourceArrLen; a++) target.SetValue(targetElementType.FromObject(valueArr.GetValue(a), encoding), a);
  260. return target;
  261. }
  262. //if (value is IList valueList)
  263. //{
  264. // var targetElementType = targetType.GetElementType();
  265. // var sourceArrLen = valueList.Count;
  266. // var target = Array.CreateInstance(targetElementType, sourceArrLen);
  267. // for (var a = 0; a < sourceArrLen; a++) target.SetValue(targetElementType.FromObject(valueList[a], encoding), a);
  268. // return target;
  269. //}
  270. }
  271. var func = _dicFromObject.GetOrAdd(targetType, tt =>
  272. {
  273. if (tt == typeof(object)) return vs => vs;
  274. if (tt == typeof(string)) return vs => vs;
  275. if (tt == typeof(char[])) return vs => vs == null ? null : vs.ToCharArray();
  276. if (tt == typeof(char)) return vs => vs == null ? default(char) : vs.ToCharArray(0, 1).FirstOrDefault();
  277. if (tt == typeof(bool)) return vs =>
  278. {
  279. if (vs == null) return false;
  280. switch (vs.ToLower())
  281. {
  282. case "true":
  283. case "1":
  284. return true;
  285. }
  286. return false;
  287. };
  288. if (tt == typeof(bool?)) return vs =>
  289. {
  290. if (vs == null) return false;
  291. switch (vs.ToLower())
  292. {
  293. case "true":
  294. case "1":
  295. return true;
  296. case "false":
  297. case "0":
  298. return false;
  299. }
  300. return null;
  301. };
  302. if (tt == typeof(byte)) return vs => vs == null ? 0 : byte.TryParse(vs, NumberStyles.Any, null, out var tryval) ? tryval : 0;
  303. if (tt == typeof(byte?)) return vs => vs == null ? null : byte.TryParse(vs, NumberStyles.Any, null, out var tryval) ? (byte?)tryval : null;
  304. if (tt == typeof(decimal)) return vs => vs == null ? 0 : decimal.TryParse(vs, NumberStyles.Any, null, out var tryval) ? tryval : 0;
  305. if (tt == typeof(decimal?)) return vs => vs == null ? null : decimal.TryParse(vs, NumberStyles.Any, null, out var tryval) ? (decimal?)tryval : null;
  306. if (tt == typeof(double)) return vs => vs == null ? 0 : double.TryParse(vs, NumberStyles.Any, null, out var tryval) ? tryval : 0;
  307. if (tt == typeof(double?)) return vs => vs == null ? null : double.TryParse(vs, NumberStyles.Any, null, out var tryval) ? (double?)tryval : null;
  308. if (tt == typeof(float)) return vs => vs == null ? 0 : float.TryParse(vs, NumberStyles.Any, null, out var tryval) ? tryval : 0;
  309. if (tt == typeof(float?)) return vs => vs == null ? null : float.TryParse(vs, NumberStyles.Any, null, out var tryval) ? (float?)tryval : null;
  310. if (tt == typeof(int)) return vs => vs == null ? 0 : int.TryParse(vs, NumberStyles.Any, null, out var tryval) ? tryval : 0;
  311. if (tt == typeof(int?)) return vs => vs == null ? null : int.TryParse(vs, NumberStyles.Any, null, out var tryval) ? (int?)tryval : null;
  312. if (tt == typeof(long)) return vs => vs == null ? 0 : long.TryParse(vs, NumberStyles.Any, null, out var tryval) ? tryval : 0;
  313. if (tt == typeof(long?)) return vs => vs == null ? null : long.TryParse(vs, NumberStyles.Any, null, out var tryval) ? (long?)tryval : null;
  314. if (tt == typeof(sbyte)) return vs => vs == null ? 0 : sbyte.TryParse(vs, NumberStyles.Any, null, out var tryval) ? tryval : 0;
  315. if (tt == typeof(sbyte?)) return vs => vs == null ? null : sbyte.TryParse(vs, NumberStyles.Any, null, out var tryval) ? (sbyte?)tryval : null;
  316. if (tt == typeof(short)) return vs => vs == null ? 0 : short.TryParse(vs, NumberStyles.Any, null, out var tryval) ? tryval : 0;
  317. if (tt == typeof(short?)) return vs => vs == null ? null : short.TryParse(vs, NumberStyles.Any, null, out var tryval) ? (short?)tryval : null;
  318. if (tt == typeof(uint)) return vs => vs == null ? 0 : uint.TryParse(vs, NumberStyles.Any, null, out var tryval) ? tryval : 0;
  319. if (tt == typeof(uint?)) return vs => vs == null ? null : uint.TryParse(vs, NumberStyles.Any, null, out var tryval) ? (uint?)tryval : null;
  320. if (tt == typeof(ulong)) return vs => vs == null ? 0 : ulong.TryParse(vs, NumberStyles.Any, null, out var tryval) ? tryval : 0;
  321. if (tt == typeof(ulong?)) return vs => vs == null ? null : ulong.TryParse(vs, NumberStyles.Any, null, out var tryval) ? (ulong?)tryval : null;
  322. if (tt == typeof(ushort)) return vs => vs == null ? 0 : ushort.TryParse(vs, NumberStyles.Any, null, out var tryval) ? tryval : 0;
  323. if (tt == typeof(ushort?)) return vs => vs == null ? null : ushort.TryParse(vs, NumberStyles.Any, null, out var tryval) ? (ushort?)tryval : null;
  324. if (tt == typeof(DateTime)) return vs => vs == null ? DateTime.MinValue : DateTime.TryParse(vs, out var tryval) ? tryval : DateTime.MinValue;
  325. if (tt == typeof(DateTime?)) return vs => vs == null ? null : DateTime.TryParse(vs, out var tryval) ? (DateTime?)tryval : null;
  326. if (tt == typeof(DateTimeOffset)) return vs => vs == null ? DateTimeOffset.MinValue : DateTimeOffset.TryParse(vs, out var tryval) ? tryval : DateTimeOffset.MinValue;
  327. if (tt == typeof(DateTimeOffset?)) return vs => vs == null ? null : DateTimeOffset.TryParse(vs, out var tryval) ? (DateTimeOffset?)tryval : null;
  328. if (tt == typeof(TimeSpan)) return vs => vs == null ? TimeSpan.Zero : TimeSpan.TryParse(vs, out var tryval) ? tryval : TimeSpan.Zero;
  329. if (tt == typeof(TimeSpan?)) return vs => vs == null ? null : TimeSpan.TryParse(vs, out var tryval) ? (TimeSpan?)tryval : null;
  330. if (tt == typeof(Guid)) return vs => vs == null ? Guid.Empty : Guid.TryParse(vs, out var tryval) ? tryval : Guid.Empty;
  331. if (tt == typeof(Guid?)) return vs => vs == null ? null : Guid.TryParse(vs, out var tryval) ? (Guid?)tryval : null;
  332. if (tt == typeof(BigInteger)) return vs => vs == null ? 0 : BigInteger.TryParse(vs, NumberStyles.Any, null, out var tryval) ? tryval : 0;
  333. if (tt == typeof(BigInteger?)) return vs => vs == null ? null : BigInteger.TryParse(vs, NumberStyles.Any, null, out var tryval) ? (BigInteger?)tryval : null;
  334. if (tt.NullableTypeOrThis().IsEnum)
  335. {
  336. var tttype = tt.NullableTypeOrThis();
  337. var ttdefval = tt.CreateInstanceGetDefaultValue();
  338. return vs =>
  339. {
  340. if (string.IsNullOrWhiteSpace(vs)) return ttdefval;
  341. return Enum.Parse(tttype, vs, true);
  342. };
  343. }
  344. var localTargetType = targetType;
  345. var localValueType = valueType;
  346. return vs =>
  347. {
  348. if (vs == null) return null;
  349. throw new NotSupportedException($"convert failed {localValueType.DisplayCsharp()} -> {localTargetType.DisplayCsharp()}");
  350. };
  351. });
  352. var valueStr = valueIsNull ? null : valueType == typeof(byte[]) ? encoding.GetString(value as byte[]) : value.ToInvariantCultureToString();
  353. return func(valueStr);
  354. }
  355. internal static string ToInvariantCultureToString(this object obj) => obj is string objstr ? objstr : string.Format(CultureInfo.InvariantCulture, @"{0}", obj);
  356. private static bool IsNullableType(this Type that) => that.IsArray == false && that?.FullName.StartsWith("System.Nullable`1[") == true;
  357. private static Type NullableTypeOrThis(this Type that) => that?.IsNullableType() == true ? that.GetGenericArguments().First() : that;
  358. internal static object CreateInstanceGetDefaultValue(this Type that)
  359. {
  360. if (that == null) return null;
  361. if (that == typeof(string)) return default(string);
  362. if (that == typeof(Guid)) return default(Guid);
  363. if (that == typeof(byte[])) return default(byte[]);
  364. if (that.IsArray) return Array.CreateInstance(that.GetElementType(), 0);
  365. if (that.IsInterface || that.IsAbstract) return null;
  366. var ctorParms = that.InternalGetTypeConstructor0OrFirst(false)?.GetParameters();
  367. if (ctorParms == null || ctorParms.Any() == false) return Activator.CreateInstance(that, true);
  368. return Activator.CreateInstance(that, ctorParms.Select(a => a.ParameterType.IsInterface ||
  369. a.ParameterType.IsAbstract ||
  370. a.ParameterType == typeof(string) ||
  371. a.ParameterType.IsArray ? null : Activator.CreateInstance(a.ParameterType, null)).ToArray());
  372. }
  373. private static ConcurrentDictionary<Type, ConstructorInfo> _dicInternalGetTypeConstructor0OrFirst = new ConcurrentDictionary<Type, ConstructorInfo>();
  374. private static ConstructorInfo InternalGetTypeConstructor0OrFirst(this Type that, bool isThrow = true)
  375. {
  376. var ret = _dicInternalGetTypeConstructor0OrFirst.GetOrAdd(that, tp =>
  377. tp.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[0], null) ??
  378. tp.GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault());
  379. if (ret == null && isThrow) throw new ArgumentException($"{that.FullName} has no method to access constructor");
  380. return ret;
  381. }
  382. private static string DisplayCsharp(this Type type, bool isNameSpace = true)
  383. {
  384. if (type == null) return null;
  385. if (type == typeof(void)) return "void";
  386. if (type.IsGenericParameter) return type.Name;
  387. if (type.IsArray) return $"{DisplayCsharp(type.GetElementType())}[]";
  388. var sb = new StringBuilder();
  389. var nestedType = type;
  390. while (nestedType.IsNested)
  391. {
  392. sb.Insert(0, ".").Insert(0, DisplayCsharp(nestedType.DeclaringType, false));
  393. nestedType = nestedType.DeclaringType;
  394. }
  395. if (isNameSpace && string.IsNullOrWhiteSpace(nestedType.Namespace) == false)
  396. sb.Insert(0, ".").Insert(0, nestedType.Namespace);
  397. if (type.IsGenericType == false)
  398. return sb.Append(type.Name).ToString();
  399. var genericParameters = type.GetGenericArguments();
  400. if (type.IsNested && type.DeclaringType.IsGenericType)
  401. {
  402. var dic = genericParameters.ToDictionary(a => a.Name);
  403. foreach (var nestedGenericParameter in type.DeclaringType.GetGenericArguments())
  404. if (dic.ContainsKey(nestedGenericParameter.Name))
  405. dic.Remove(nestedGenericParameter.Name);
  406. genericParameters = dic.Values.ToArray();
  407. }
  408. if (genericParameters.Any() == false)
  409. return sb.Append(type.Name).ToString();
  410. sb.Append(type.Name.Remove(type.Name.IndexOf('`'))).Append("<");
  411. var genericTypeIndex = 0;
  412. foreach (var genericType in genericParameters)
  413. {
  414. if (genericTypeIndex++ > 0) sb.Append(", ");
  415. sb.Append(DisplayCsharp(genericType, true));
  416. }
  417. return sb.Append(">").ToString();
  418. }
  419. }
  420. }