Helpers.cs 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601
  1. 
  2. using System;
  3. using System.Collections;
  4. #if FEAT_IKVM
  5. using Type = IKVM.Reflection.Type;
  6. using IKVM.Reflection;
  7. #else
  8. using System.Reflection;
  9. #endif
  10. namespace ProtoBuf
  11. {
  12. /// <summary>
  13. /// Not all frameworks are created equal (fx1.1 vs fx2.0,
  14. /// micro-framework, compact-framework,
  15. /// silverlight, etc). This class simply wraps up a few things that would
  16. /// otherwise make the real code unnecessarily messy, providing fallback
  17. /// implementations if necessary.
  18. /// </summary>
  19. internal sealed class Helpers
  20. {
  21. private Helpers() { }
  22. public static System.Text.StringBuilder AppendLine(System.Text.StringBuilder builder)
  23. {
  24. #if CF2
  25. return builder.Append("\r\n");
  26. #elif FX11
  27. return builder.Append(Environment.NewLine);
  28. #else
  29. return builder.AppendLine();
  30. #endif
  31. }
  32. public static bool IsNullOrEmpty(string value)
  33. { // yes, FX11 lacks this!
  34. return value == null || value.Length == 0;
  35. }
  36. [System.Diagnostics.Conditional("DEBUG")]
  37. public static void DebugWriteLine(string message, object obj)
  38. {
  39. #if DEBUG
  40. string suffix;
  41. try
  42. {
  43. suffix = obj == null ? "(null)" : obj.ToString();
  44. }
  45. catch
  46. {
  47. suffix = "(exception)";
  48. }
  49. DebugWriteLine(message + ": " + suffix);
  50. #endif
  51. }
  52. [System.Diagnostics.Conditional("DEBUG")]
  53. public static void DebugWriteLine(string message)
  54. {
  55. #if DEBUG
  56. #if MF
  57. Microsoft.SPOT.Debug.Print(message);
  58. #else
  59. System.Diagnostics.Debug.WriteLine(message);
  60. #endif
  61. #endif
  62. }
  63. [System.Diagnostics.Conditional("TRACE")]
  64. public static void TraceWriteLine(string message)
  65. {
  66. #if TRACE
  67. #if MF
  68. Microsoft.SPOT.Trace.Print(message);
  69. #elif SILVERLIGHT || MONODROID || CF2 || WINRT || IOS || PORTABLE
  70. System.Diagnostics.Debug.WriteLine(message);
  71. #else
  72. System.Diagnostics.Trace.WriteLine(message);
  73. #endif
  74. #endif
  75. }
  76. [System.Diagnostics.Conditional("DEBUG")]
  77. public static void DebugAssert(bool condition, string message)
  78. {
  79. #if DEBUG
  80. if (!condition)
  81. {
  82. #if MF
  83. Microsoft.SPOT.Debug.Assert(false, message);
  84. #else
  85. System.Diagnostics.Debug.Assert(false, message);
  86. }
  87. #endif
  88. #endif
  89. }
  90. [System.Diagnostics.Conditional("DEBUG")]
  91. public static void DebugAssert(bool condition, string message, params object[] args)
  92. {
  93. #if DEBUG
  94. if (!condition) DebugAssert(false, string.Format(message, args));
  95. #endif
  96. }
  97. [System.Diagnostics.Conditional("DEBUG")]
  98. public static void DebugAssert(bool condition)
  99. {
  100. #if DEBUG
  101. #if MF
  102. Microsoft.SPOT.Debug.Assert(condition);
  103. #else
  104. if(!condition && System.Diagnostics.Debugger.IsAttached) System.Diagnostics.Debugger.Break();
  105. System.Diagnostics.Debug.Assert(condition);
  106. #endif
  107. #endif
  108. }
  109. #if !NO_RUNTIME
  110. public static void Sort(int[] keys, object[] values)
  111. {
  112. // bubble-sort; it'll work on MF, has small code,
  113. // and works well-enough for our sizes. This approach
  114. // also allows us to do `int` compares without having
  115. // to go via IComparable etc, so win:win
  116. bool swapped;
  117. do {
  118. swapped = false;
  119. for (int i = 1; i < keys.Length; i++) {
  120. if (keys[i - 1] > keys[i]) {
  121. int tmpKey = keys[i];
  122. keys[i] = keys[i - 1];
  123. keys[i - 1] = tmpKey;
  124. object tmpValue = values[i];
  125. values[i] = values[i - 1];
  126. values[i - 1] = tmpValue;
  127. swapped = true;
  128. }
  129. }
  130. } while (swapped);
  131. }
  132. #endif
  133. public static void BlockCopy(byte[] from, int fromIndex, byte[] to, int toIndex, int count)
  134. {
  135. #if MF || WINRT
  136. Array.Copy(from, fromIndex, to, toIndex, count);
  137. #else
  138. Buffer.BlockCopy(from, fromIndex, to, toIndex, count);
  139. #endif
  140. }
  141. public static bool IsInfinity(float value)
  142. {
  143. #if MF
  144. const float inf = (float)1.0 / (float)0.0, minf = (float)-1.0F / (float)0.0;
  145. return value == inf || value == minf;
  146. #else
  147. return float.IsInfinity(value);
  148. #endif
  149. }
  150. #if WINRT
  151. internal static MemberInfo GetInstanceMember(TypeInfo declaringType, string name)
  152. {
  153. PropertyInfo prop = declaringType.GetDeclaredProperty(name);
  154. MethodInfo method;
  155. if (prop != null && (method = Helpers.GetGetMethod(prop, true, true)) != null && !method.IsStatic) return prop;
  156. FieldInfo field = declaringType.GetDeclaredField(name);
  157. if (field != null && !field.IsStatic) return field;
  158. return null;
  159. }
  160. internal static MethodInfo GetInstanceMethod(TypeInfo declaringType, string name)
  161. {
  162. foreach (MethodInfo method in declaringType.DeclaredMethods)
  163. {
  164. if (!method.IsStatic && method.Name == name)
  165. {
  166. return method;
  167. }
  168. }
  169. return null;
  170. }
  171. internal static MethodInfo GetStaticMethod(TypeInfo declaringType, string name)
  172. {
  173. foreach (MethodInfo method in declaringType.DeclaredMethods)
  174. {
  175. if (method.IsStatic && method.Name == name)
  176. {
  177. return method;
  178. }
  179. }
  180. return null;
  181. }
  182. internal static MethodInfo GetInstanceMethod(Type declaringType, string name, Type[] types)
  183. {
  184. return GetInstanceMethod(declaringType.GetTypeInfo(), name, types);
  185. }
  186. internal static MethodInfo GetInstanceMethod(TypeInfo declaringType, string name, Type[] types)
  187. {
  188. if (types == null) types = EmptyTypes;
  189. foreach (MethodInfo method in declaringType.DeclaredMethods)
  190. {
  191. if (!method.IsStatic && method.Name == name)
  192. {
  193. if(IsMatch(method.GetParameters(), types)) return method;
  194. }
  195. }
  196. return null;
  197. }
  198. #else
  199. internal static MethodInfo GetInstanceMethod(Type declaringType, string name)
  200. {
  201. return declaringType.GetMethod(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
  202. }
  203. internal static MethodInfo GetStaticMethod(Type declaringType, string name)
  204. {
  205. return declaringType.GetMethod(name, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
  206. }
  207. internal static MethodInfo GetInstanceMethod(Type declaringType, string name, Type[] types)
  208. {
  209. if(types == null) types = EmptyTypes;
  210. #if PORTABLE
  211. MethodInfo method = declaringType.GetMethod(name, types);
  212. if (method != null && method.IsStatic) method = null;
  213. return method;
  214. #else
  215. return declaringType.GetMethod(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
  216. null, types, null);
  217. #endif
  218. }
  219. #endif
  220. internal static bool IsSubclassOf(Type type, Type baseClass)
  221. {
  222. #if WINRT
  223. return type.GetTypeInfo().IsSubclassOf(baseClass);
  224. #else
  225. return type.IsSubclassOf(baseClass);
  226. #endif
  227. }
  228. public static bool IsInfinity(double value)
  229. {
  230. #if MF
  231. const double inf = (double)1.0 / (double)0.0, minf = (double)-1.0F / (double)0.0;
  232. return value == inf || value == minf;
  233. #else
  234. return double.IsInfinity(value);
  235. #endif
  236. }
  237. public readonly static Type[] EmptyTypes =
  238. #if PORTABLE || WINRT || CF2 || CF35
  239. new Type[0];
  240. #else
  241. Type.EmptyTypes;
  242. #endif
  243. #if WINRT
  244. private static readonly Type[] knownTypes = new Type[] {
  245. typeof(bool), typeof(char), typeof(sbyte), typeof(byte),
  246. typeof(short), typeof(ushort), typeof(int), typeof(uint),
  247. typeof(long), typeof(ulong), typeof(float), typeof(double),
  248. typeof(decimal), typeof(string),
  249. typeof(DateTime), typeof(TimeSpan), typeof(Guid), typeof(Uri),
  250. typeof(byte[]), typeof(System.Type)};
  251. private static readonly ProtoTypeCode[] knownCodes = new ProtoTypeCode[] {
  252. ProtoTypeCode.Boolean, ProtoTypeCode.Char, ProtoTypeCode.SByte, ProtoTypeCode.Byte,
  253. ProtoTypeCode.Int16, ProtoTypeCode.UInt16, ProtoTypeCode.Int32, ProtoTypeCode.UInt32,
  254. ProtoTypeCode.Int64, ProtoTypeCode.UInt64, ProtoTypeCode.Single, ProtoTypeCode.Double,
  255. ProtoTypeCode.Decimal, ProtoTypeCode.String,
  256. ProtoTypeCode.DateTime, ProtoTypeCode.TimeSpan, ProtoTypeCode.Guid, ProtoTypeCode.Uri,
  257. ProtoTypeCode.ByteArray, ProtoTypeCode.Type
  258. };
  259. #endif
  260. #if FEAT_IKVM
  261. public static ProtoTypeCode GetTypeCode(IKVM.Reflection.Type type)
  262. {
  263. TypeCode code = IKVM.Reflection.Type.GetTypeCode(type);
  264. switch (code)
  265. {
  266. case TypeCode.Empty:
  267. case TypeCode.Boolean:
  268. case TypeCode.Char:
  269. case TypeCode.SByte:
  270. case TypeCode.Byte:
  271. case TypeCode.Int16:
  272. case TypeCode.UInt16:
  273. case TypeCode.Int32:
  274. case TypeCode.UInt32:
  275. case TypeCode.Int64:
  276. case TypeCode.UInt64:
  277. case TypeCode.Single:
  278. case TypeCode.Double:
  279. case TypeCode.Decimal:
  280. case TypeCode.DateTime:
  281. case TypeCode.String:
  282. return (ProtoTypeCode)code;
  283. }
  284. switch(type.FullName)
  285. {
  286. case "System.TimeSpan": return ProtoTypeCode.TimeSpan;
  287. case "System.Guid": return ProtoTypeCode.Guid;
  288. case "System.Uri": return ProtoTypeCode.Uri;
  289. case "System.Byte[]": return ProtoTypeCode.ByteArray;
  290. case "System.Type": return ProtoTypeCode.Type;
  291. }
  292. return ProtoTypeCode.Unknown;
  293. }
  294. #endif
  295. public static ProtoTypeCode GetTypeCode(System.Type type)
  296. {
  297. #if WINRT
  298. int idx = Array.IndexOf<Type>(knownTypes, type);
  299. if (idx >= 0) return knownCodes[idx];
  300. return type == null ? ProtoTypeCode.Empty : ProtoTypeCode.Unknown;
  301. #else
  302. TypeCode code = System.Type.GetTypeCode(type);
  303. switch (code)
  304. {
  305. case TypeCode.Empty:
  306. case TypeCode.Boolean:
  307. case TypeCode.Char:
  308. case TypeCode.SByte:
  309. case TypeCode.Byte:
  310. case TypeCode.Int16:
  311. case TypeCode.UInt16:
  312. case TypeCode.Int32:
  313. case TypeCode.UInt32:
  314. case TypeCode.Int64:
  315. case TypeCode.UInt64:
  316. case TypeCode.Single:
  317. case TypeCode.Double:
  318. case TypeCode.Decimal:
  319. case TypeCode.DateTime:
  320. case TypeCode.String:
  321. return (ProtoTypeCode)code;
  322. }
  323. if (type == typeof(TimeSpan)) return ProtoTypeCode.TimeSpan;
  324. if (type == typeof(Guid)) return ProtoTypeCode.Guid;
  325. if (type == typeof(Uri)) return ProtoTypeCode.Uri;
  326. if (type == typeof(byte[])) return ProtoTypeCode.ByteArray;
  327. if (type == typeof(System.Type)) return ProtoTypeCode.Type;
  328. return ProtoTypeCode.Unknown;
  329. #endif
  330. }
  331. #if FEAT_IKVM
  332. internal static IKVM.Reflection.Type GetUnderlyingType(IKVM.Reflection.Type type)
  333. {
  334. if (type.IsValueType && type.IsGenericType && type.GetGenericTypeDefinition().FullName == "System.Nullable`1")
  335. {
  336. return type.GetGenericArguments()[0];
  337. }
  338. return null;
  339. }
  340. #endif
  341. internal static System.Type GetUnderlyingType(System.Type type)
  342. {
  343. #if NO_GENERICS
  344. return null; // never a Nullable<T>, so always returns null
  345. #else
  346. return Nullable.GetUnderlyingType(type);
  347. #endif
  348. }
  349. internal static bool IsValueType(Type type)
  350. {
  351. #if WINRT
  352. return type.GetTypeInfo().IsValueType;
  353. #else
  354. return type.IsValueType;
  355. #endif
  356. }
  357. internal static bool IsEnum(Type type)
  358. {
  359. #if WINRT
  360. return type.GetTypeInfo().IsEnum;
  361. #else
  362. return type.IsEnum;
  363. #endif
  364. }
  365. internal static MethodInfo GetGetMethod(PropertyInfo property, bool nonPublic, bool allowInternal)
  366. {
  367. if (property == null) return null;
  368. #if WINRT
  369. MethodInfo method = property.GetMethod;
  370. if (!nonPublic && method != null && !method.IsPublic) method = null;
  371. return method;
  372. #else
  373. MethodInfo method = property.GetGetMethod(nonPublic);
  374. if (method == null && !nonPublic && allowInternal)
  375. { // could be "internal" or "protected internal"; look for a non-public, then back-check
  376. method = property.GetGetMethod(true);
  377. if (method == null && !(method.IsAssembly || method.IsFamilyOrAssembly))
  378. {
  379. method = null;
  380. }
  381. }
  382. return method;
  383. #endif
  384. }
  385. internal static MethodInfo GetSetMethod(PropertyInfo property, bool nonPublic, bool allowInternal)
  386. {
  387. if (property == null) return null;
  388. #if WINRT
  389. MethodInfo method = property.SetMethod;
  390. if (!nonPublic && method != null && !method.IsPublic) method = null;
  391. return method;
  392. #else
  393. MethodInfo method = property.GetSetMethod(nonPublic);
  394. if (method == null && !nonPublic && allowInternal)
  395. { // could be "internal" or "protected internal"; look for a non-public, then back-check
  396. method = property.GetGetMethod(true);
  397. if (method == null && !(method.IsAssembly || method.IsFamilyOrAssembly))
  398. {
  399. method = null;
  400. }
  401. }
  402. return method;
  403. #endif
  404. }
  405. #if FEAT_IKVM
  406. internal static bool IsMatch(IKVM.Reflection.ParameterInfo[] parameters, IKVM.Reflection.Type[] parameterTypes)
  407. {
  408. if (parameterTypes == null) parameterTypes = Helpers.EmptyTypes;
  409. if (parameters.Length != parameterTypes.Length) return false;
  410. for (int i = 0; i < parameters.Length; i++)
  411. {
  412. if (parameters[i].ParameterType != parameterTypes[i]) return false;
  413. }
  414. return true;
  415. }
  416. #endif
  417. #if WINRT
  418. private static bool IsMatch(ParameterInfo[] parameters, Type[] parameterTypes)
  419. {
  420. if (parameterTypes == null) parameterTypes = EmptyTypes;
  421. if (parameters.Length != parameterTypes.Length) return false;
  422. for (int i = 0; i < parameters.Length; i++)
  423. {
  424. if (parameters[i].ParameterType != parameterTypes[i]) return false;
  425. }
  426. return true;
  427. }
  428. internal static ConstructorInfo GetConstructor(TypeInfo type, Type[] parameterTypes, bool nonPublic)
  429. {
  430. foreach (ConstructorInfo ctor in type.DeclaredConstructors)
  431. {
  432. if (!nonPublic && !ctor.IsPublic) continue;
  433. if (IsMatch(ctor.GetParameters(), parameterTypes)) return ctor;
  434. }
  435. return null;
  436. }
  437. internal static ConstructorInfo[] GetConstructors(TypeInfo typeInfo, bool nonPublic)
  438. {
  439. if (nonPublic) return System.Linq.Enumerable.ToArray(typeInfo.DeclaredConstructors);
  440. return System.Linq.Enumerable.ToArray(
  441. System.Linq.Enumerable.Where(typeInfo.DeclaredConstructors, x => x.IsPublic));
  442. }
  443. internal static PropertyInfo GetProperty(TypeInfo type, string name, bool nonPublic)
  444. {
  445. return type.GetDeclaredProperty(name);
  446. }
  447. #else
  448. internal static ConstructorInfo GetConstructor(Type type, Type[] parameterTypes, bool nonPublic)
  449. {
  450. #if PORTABLE
  451. // pretty sure this will only ever return public, but...
  452. ConstructorInfo ctor = type.GetConstructor(parameterTypes);
  453. return (ctor != null && (nonPublic || ctor.IsPublic)) ? ctor : null;
  454. #else
  455. return type.GetConstructor(
  456. nonPublic ? BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic
  457. : BindingFlags.Instance | BindingFlags.Public,
  458. null, parameterTypes, null);
  459. #endif
  460. }
  461. internal static ConstructorInfo[] GetConstructors(Type type, bool nonPublic)
  462. {
  463. return type.GetConstructors(
  464. nonPublic ? BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic
  465. : BindingFlags.Instance | BindingFlags.Public);
  466. }
  467. internal static PropertyInfo GetProperty(Type type, string name, bool nonPublic)
  468. {
  469. return type.GetProperty(name,
  470. nonPublic ? BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic
  471. : BindingFlags.Instance | BindingFlags.Public);
  472. }
  473. #endif
  474. internal static object ParseEnum(Type type, string value)
  475. {
  476. #if FEAT_IKVM
  477. FieldInfo[] fields = type.GetFields();
  478. foreach (FieldInfo field in fields)
  479. {
  480. if (string.Equals(field.Name, value, StringComparison.OrdinalIgnoreCase)) return field.GetRawConstantValue();
  481. }
  482. throw new ArgumentException("Enum value could not be parsed: " + value + ", " + type.FullName);
  483. #else
  484. return Enum.Parse(type, value, true);
  485. #endif
  486. }
  487. internal static MemberInfo[] GetInstanceFieldsAndProperties(Type type, bool publicOnly)
  488. {
  489. #if WINRT
  490. System.Collections.Generic.List<MemberInfo> members = new System.Collections.Generic.List<MemberInfo>();
  491. foreach(FieldInfo field in type.GetRuntimeFields())
  492. {
  493. if(field.IsStatic) continue;
  494. if(field.IsPublic || !publicOnly) members.Add(field);
  495. }
  496. foreach(PropertyInfo prop in type.GetRuntimeProperties())
  497. {
  498. MethodInfo getter = Helpers.GetGetMethod(prop, true, true);
  499. if(getter == null || getter.IsStatic) continue;
  500. if(getter.IsPublic || !publicOnly) members.Add(prop);
  501. }
  502. return members.ToArray();
  503. #else
  504. BindingFlags flags = publicOnly ? BindingFlags.Public | BindingFlags.Instance : BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic;
  505. PropertyInfo[] props = type.GetProperties(flags);
  506. FieldInfo[] fields = type.GetFields(flags);
  507. MemberInfo[] members = new MemberInfo[fields.Length + props.Length];
  508. props.CopyTo(members, 0);
  509. fields.CopyTo(members, props.Length);
  510. return members;
  511. #endif
  512. }
  513. internal static Type GetMemberType(MemberInfo member)
  514. {
  515. #if WINRT || PORTABLE
  516. PropertyInfo prop = member as PropertyInfo;
  517. if (prop != null) return prop.PropertyType;
  518. FieldInfo fld = member as FieldInfo;
  519. return fld == null ? null : fld.FieldType;
  520. #else
  521. switch(member.MemberType)
  522. {
  523. case MemberTypes.Field: return ((FieldInfo) member).FieldType;
  524. case MemberTypes.Property: return ((PropertyInfo) member).PropertyType;
  525. default: return null;
  526. }
  527. #endif
  528. }
  529. internal static bool IsAssignableFrom(Type target, Type type)
  530. {
  531. #if WINRT
  532. return target.GetTypeInfo().IsAssignableFrom(type.GetTypeInfo());
  533. #else
  534. return target.IsAssignableFrom(type);
  535. #endif
  536. }
  537. }
  538. /// <summary>
  539. /// Intended to be a direct map to regular TypeCode, but:
  540. /// - with missing types
  541. /// - existing on WinRT
  542. /// </summary>
  543. internal enum ProtoTypeCode
  544. {
  545. Empty = 0,
  546. Unknown = 1, // maps to TypeCode.Object
  547. Boolean = 3,
  548. Char = 4,
  549. SByte = 5,
  550. Byte = 6,
  551. Int16 = 7,
  552. UInt16 = 8,
  553. Int32 = 9,
  554. UInt32 = 10,
  555. Int64 = 11,
  556. UInt64 = 12,
  557. Single = 13,
  558. Double = 14,
  559. Decimal = 15,
  560. DateTime = 16,
  561. String = 18,
  562. // additions
  563. TimeSpan = 100,
  564. ByteArray = 101,
  565. Guid = 102,
  566. Uri = 103,
  567. Type = 104
  568. }
  569. }