Helpers.cs 24 KB

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