Helpers.cs 24 KB

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