PageRenderTime 1703ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/eLMM/VirusCount/Escience/Parse/Parser.cs

#
C# | 430 lines | 252 code | 49 blank | 129 comment | 52 complexity | 17164d1ad3f8fb3ddf28de12a941717c MD5 | raw file
  1. //*********************************************************
  2. //
  3. // Copyright (c) Microsoft. All rights reserved.
  4. // This code is licensed under the Apache License, Version 2.0.
  5. // THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
  6. // ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
  7. // IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
  8. // PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
  9. //
  10. //*********************************************************
  11. using System;
  12. using System.Collections.Generic;
  13. using System.Linq;
  14. using System.Reflection;
  15. using Bio.Util;
  16. namespace MBT.Escience.Parse
  17. {
  18. public static class Parser
  19. {
  20. /// <summary>
  21. /// Checks if this type has a Parse or TryParse static method that takes a string as the argument.
  22. /// </summary>
  23. /// <param name="type"></param>
  24. /// <returns></returns>
  25. public static bool HasParseMethod(this Type type)
  26. {
  27. MethodInfo tryParse = type.GetMethod("TryParse", new Type[] { typeof(string), type.MakeByRefType() });
  28. if (tryParse != null && tryParse.IsStatic)
  29. return true;
  30. MethodInfo parse = type.GetMethod("Parse", new Type[] { typeof(string) });
  31. if (parse != null && parse.IsStatic)
  32. return true;
  33. return false;
  34. }
  35. public static bool TryParseAll<T>(IEnumerable<string> values, out IList<T> result)
  36. {
  37. result = new List<T>();
  38. foreach (string s in values)
  39. {
  40. T value;
  41. if (TryParse<T>(s, out value))
  42. {
  43. result.Add(value);
  44. }
  45. else
  46. {
  47. return false;
  48. }
  49. }
  50. return true;
  51. }
  52. public static IEnumerable<T> ParseAll<T>(IEnumerable<string> values)
  53. {
  54. foreach (string s in values)
  55. {
  56. yield return Parse<T>(s);
  57. }
  58. }
  59. /// <summary>
  60. /// This method should be updated to use the rest of the methods in this class.
  61. /// </summary>
  62. /// <param name="field"></param>
  63. /// <param name="type"></param>
  64. /// <returns></returns>
  65. public static object Parse(string field, Type type)
  66. {
  67. var potentialMethods = typeof(Parser).GetMethods().Where(m => m.Name == "Parse" && m.IsGenericMethod);
  68. MethodInfo parseInfo = potentialMethods.First().MakeGenericMethod(type);
  69. object[] parameters = new object[] { field };
  70. return parseInfo.Invoke(null, parameters);
  71. //if (type.Equals(typeof(string)))
  72. //{
  73. // return field;
  74. //}
  75. //if (type.Equals(typeof(int)))
  76. //{
  77. // return int.Parse(field);
  78. //}
  79. //if (type.Equals(typeof(double)))
  80. //{
  81. // return double.Parse(field);
  82. //}
  83. //if (type.Equals(typeof(bool)))
  84. //{
  85. // return bool.Parse(field);
  86. //}
  87. //if (type.Equals(typeof(char)))
  88. //{
  89. // return char.Parse(field);
  90. //}
  91. //if (type.Equals(typeof(DateTime)))
  92. //{
  93. // return DateTime.Parse(field);
  94. //}
  95. //Helper.CheckCondition<ParseException>(false, "Don't know how to parse type " + type.Name);
  96. //return null;
  97. }
  98. /// <summary>
  99. /// Will parse s into T, provided T has a Parse(string) or TryParse(string s, out T t) method defined, or is one of the magical
  100. /// special cases we've implemented (including ICollection (comma delimited), Nullable and Enums).
  101. /// </summary>
  102. /// <typeparam name="T"></typeparam>
  103. /// <param name="s"></param>
  104. /// <returns></returns>
  105. public static T Parse<T>(string s)
  106. {
  107. s = s.Trim();
  108. T t;
  109. if (TryParse(s, out t))
  110. {
  111. return t;
  112. }
  113. else
  114. {
  115. throw new ArgumentException(string.Format("Could not parse \"{0}\" into an instance of type {1}", s, typeof(T)));
  116. }
  117. }
  118. /// <summary>
  119. /// Will parse s into T, provided T has a Parse(string) or TryParse(string s, out T t) method defined, or is one of the magical
  120. /// special cases we've implemented (including ICollection (comma delimited), Nullable and Enums).
  121. /// </summary>
  122. /// <typeparam name="T"></typeparam>
  123. /// <param name="s"></param>
  124. /// <returns></returns>
  125. public static bool TryParse<T>(string s, out T t)
  126. {
  127. s = s.Trim();
  128. Type type = typeof(T);
  129. if (s.Equals("help", StringComparison.CurrentCultureIgnoreCase))
  130. {
  131. throw ArgumentCollection.GetHelpOnKnownSubtypes(type);
  132. }
  133. else if (s.Equals("help!", StringComparison.CurrentCultureIgnoreCase))
  134. {
  135. throw ArgumentCollection.CreateHelpMessage(type);
  136. }
  137. else if (s.Equals("null", StringComparison.CurrentCultureIgnoreCase) && type.IsClass)
  138. {
  139. t = default(T); // return null
  140. return true;
  141. }
  142. else if (s is T)
  143. {
  144. return StringTryParse(s, out t);
  145. }
  146. else if (type.IsEnum)
  147. {
  148. return EnumTryParse(s, out t);
  149. }
  150. else if (type.IsGenericType)
  151. {
  152. //if (type.FindInterfaces(Module.FilterTypeNameIgnoreCase, "ICollection*").Length > 0)
  153. if (type.ParseAsCollection())
  154. {
  155. return CollectionsTryParse(s, out t);
  156. }
  157. else if (type.Name.StartsWith("Nullable"))
  158. {
  159. return NullableTryParse(s, out t);
  160. }
  161. }
  162. return GenericTryParse(s, out t);
  163. }
  164. private static bool NullableTryParse<T>(string s, out T t)
  165. {
  166. t = default(T);
  167. if (string.IsNullOrEmpty(s) || s.Equals("null", StringComparison.CurrentCultureIgnoreCase))
  168. {
  169. return true;
  170. }
  171. Type type = typeof(T);
  172. Type underlyingType = type.GetGenericArguments()[0];
  173. //underlyingType.TypeInitializer
  174. MethodInfo tryParse = typeof(Parser).GetMethod("TryParse", BindingFlags.Public | BindingFlags.Static);
  175. MethodInfo genericTryParse = tryParse.MakeGenericMethod(underlyingType);
  176. object[] args = new object[] { s, Activator.CreateInstance(underlyingType) };
  177. bool success = (bool)genericTryParse.Invoke(null, args);
  178. if (success)
  179. {
  180. t = (T)args[1];
  181. }
  182. return success;
  183. }
  184. private static bool StringTryParse<T>(string s, out T t)
  185. {
  186. t = (T)(object)s;
  187. return true;
  188. }
  189. private static bool CollectionsTryParse<T>(string s, out T t)
  190. {
  191. Type type = typeof(T);
  192. Type genericType = type.GetGenericArguments()[0];
  193. MethodInfo collectionTryParse = typeof(Parser).GetMethod("GenericCollectionsTryParse", BindingFlags.NonPublic | BindingFlags.Static);
  194. MethodInfo genericCollectionTryParse = collectionTryParse.MakeGenericMethod(type, genericType);
  195. t = default(T);
  196. object[] args = new object[] { s, t };
  197. bool success = (bool)genericCollectionTryParse.Invoke(null, args);
  198. if (success)
  199. {
  200. t = (T)args[1];
  201. }
  202. return success;
  203. }
  204. private static bool GenericCollectionsTryParse<T, S>(string s, out T t) where T : ICollection<S>, new()
  205. {
  206. t = new T();
  207. // remove wrapping parens if present
  208. if (s.StartsWith("(") && s.EndsWith(")"))
  209. s = s.Substring(1, s.Length - 2);
  210. //If the string is empty, then the list will be empty
  211. if (s == "")
  212. {
  213. return true;
  214. }
  215. foreach (string itemAsString in s.ProtectedSplit('(', ')', false, ','))
  216. {
  217. S item;
  218. if (TryParse<S>(itemAsString, out item))
  219. {
  220. t.Add(item);
  221. }
  222. else
  223. {
  224. t = default(T);
  225. return false;
  226. }
  227. }
  228. return true;
  229. }
  230. private static bool EnumTryParse<T>(string s, out T t)
  231. {
  232. int i;
  233. if (int.TryParse(s, out i))
  234. {
  235. t = (T)(object)i;
  236. return true;
  237. }
  238. try
  239. {
  240. t = (T)Enum.Parse(typeof(T), s, true);
  241. return true;
  242. }
  243. catch (ArgumentException)
  244. {
  245. }
  246. t = default(T);
  247. return false;
  248. }
  249. //private static bool NullableTryParse<T>(string s, out T t) where T:System.Nullable
  250. //{
  251. // if (string.IsNullOrEmpty(s) || s.Equals("null", StringComparison.CurrentCultureIgnoreCase))
  252. // {
  253. // return null;
  254. // }
  255. //}
  256. private static bool GenericTryParse<T>(string s, out T t)
  257. {
  258. return GenericParser<T>.TryParse(s, out t);
  259. //// now the general one.
  260. //bool success = false;
  261. //t = default(T);
  262. //Type type = typeof(T);
  263. //MethodInfo tryParse = type.GetMethod("TryParse", new Type[] { typeof(string), type.MakeByRefType() });
  264. //if (tryParse != null && tryParse.IsStatic)
  265. //{
  266. // object[] args = new object[] { s, t };
  267. // success = (bool)tryParse.Invoke(null, args);
  268. // if (success)
  269. // {
  270. // t = (T)args[1];
  271. // }
  272. //}
  273. //else
  274. //{
  275. // MethodInfo parse = type.GetMethod("Parse", new Type[] { typeof(string) });
  276. // if (parse != null && parse.IsStatic)
  277. // {
  278. // Helper.CheckCondition<ParseException>(parse != null, "Cannot parse type {0}. It does not have a TryParse or Parse method defined", typeof(T).ToTypeString());
  279. // try
  280. // {
  281. // object[] args = new object[] { s };
  282. // t = (T)parse.Invoke(null, args);
  283. // success = true;
  284. // }
  285. // catch (TargetInvocationException e)
  286. // {
  287. // if (e.InnerException is HelpException || e.InnerException is ParseException)
  288. // throw e.InnerException;
  289. // }
  290. // }
  291. // else //if (type.IsParsable() || type.IsInterface || type.IsAbstract)
  292. // {
  293. // ConstructorArguments constLine = new ConstructorArguments(s);
  294. // try
  295. // {
  296. // t = constLine.Construct<T>();
  297. // success = true;
  298. // }
  299. // catch (HelpException)
  300. // {
  301. // throw;
  302. // }
  303. // catch (ParseException)
  304. // {
  305. // throw;
  306. // }
  307. // }
  308. // //else
  309. // //{
  310. // // throw new ParseException("Cannot parse type {0}. It does not have a TryParse or Parse method defined, nor does it have a public default constructor, nor is it an interface or abstract type.", typeof(T).ToTypeString());
  311. // //}
  312. //}
  313. //return success;
  314. }
  315. private static class GenericParser<T>
  316. {
  317. private static MethodInfo _tryParse, _parse;
  318. static GenericParser()
  319. {
  320. Type type = typeof(T);
  321. _tryParse = type.GetMethod("TryParse", new Type[] { typeof(string), type.MakeByRefType() });
  322. if (_tryParse != null && !_tryParse.IsStatic)
  323. _tryParse = null;
  324. if (_tryParse == null)
  325. {
  326. _parse = type.GetMethod("Parse", new Type[] { typeof(string) });
  327. if (_parse != null && !_parse.IsStatic)
  328. _parse = null;
  329. }
  330. }
  331. public static bool IsParsable()
  332. {
  333. return _tryParse != null || _parse != null;
  334. }
  335. public static bool TryParse(string s, out T t)
  336. {
  337. //Helper.CheckCondition(IsParsable(), "Cannot parse type {0}. It does not have a TryParse or Parse method defined", typeof(T));
  338. // now the general one.
  339. bool success = false;
  340. t = default(T);
  341. if (_tryParse != null)
  342. {
  343. object[] args = new object[] { s, t };
  344. success = (bool)_tryParse.Invoke(null, args);
  345. if (success)
  346. {
  347. t = (T)args[1];
  348. }
  349. }
  350. else if (_parse != null)
  351. {
  352. try
  353. {
  354. object[] args = new object[] { s };
  355. t = (T)_parse.Invoke(null, args);
  356. success = true;
  357. }
  358. catch { }
  359. }
  360. else
  361. {
  362. ConstructorArguments constLine = new ConstructorArguments(s);
  363. try
  364. {
  365. t = constLine.Construct<T>();
  366. success = true;
  367. }
  368. catch (HelpException)
  369. {
  370. throw;
  371. }
  372. catch (ParseException)
  373. {
  374. throw;
  375. }
  376. }
  377. return success;
  378. }
  379. }
  380. }
  381. }