CallbackSet.cs 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. #if !NO_RUNTIME
  2. using System;
  3. #if FEAT_IKVM
  4. using Type = IKVM.Reflection.Type;
  5. using IKVM.Reflection;
  6. #else
  7. using System.Reflection;
  8. #endif
  9. namespace ProtoBuf.Meta
  10. {
  11. /// <summary>
  12. /// Represents the set of serialization callbacks to be used when serializing/deserializing a type.
  13. /// </summary>
  14. public class CallbackSet
  15. {
  16. private readonly MetaType metaType;
  17. internal CallbackSet(MetaType metaType)
  18. {
  19. if (metaType == null) throw new ArgumentNullException("metaType");
  20. this.metaType = metaType;
  21. }
  22. internal MethodInfo this[TypeModel.CallbackType callbackType]
  23. {
  24. get
  25. {
  26. switch (callbackType)
  27. {
  28. case TypeModel.CallbackType.BeforeSerialize: return beforeSerialize;
  29. case TypeModel.CallbackType.AfterSerialize: return afterSerialize;
  30. case TypeModel.CallbackType.BeforeDeserialize: return beforeDeserialize;
  31. case TypeModel.CallbackType.AfterDeserialize: return afterDeserialize;
  32. default: throw new ArgumentException("Callback type not supported: " + callbackType.ToString(), "callbackType");
  33. }
  34. }
  35. }
  36. internal static bool CheckCallbackParameters(TypeModel model, MethodInfo method)
  37. {
  38. ParameterInfo[] args = method.GetParameters();
  39. for (int i = 0; i < args.Length; i++)
  40. {
  41. Type paramType = args[i].ParameterType;
  42. if(paramType == model.MapType(typeof(SerializationContext))) {}
  43. else if(paramType == model.MapType(typeof(System.Type))) {}
  44. #if PLAT_BINARYFORMATTER
  45. else if(paramType == model.MapType(typeof(System.Runtime.Serialization.StreamingContext))) {}
  46. #endif
  47. else return false;
  48. }
  49. return true;
  50. }
  51. private MethodInfo SanityCheckCallback(TypeModel model, MethodInfo callback)
  52. {
  53. metaType.ThrowIfFrozen();
  54. if (callback == null) return callback; // fine
  55. if (callback.IsStatic) throw new ArgumentException("Callbacks cannot be static", "callback");
  56. if (callback.ReturnType != model.MapType(typeof(void))
  57. || !CheckCallbackParameters(model, callback))
  58. {
  59. throw CreateInvalidCallbackSignature(callback);
  60. }
  61. return callback;
  62. }
  63. internal static Exception CreateInvalidCallbackSignature(MethodInfo method)
  64. {
  65. return new NotSupportedException("Invalid callback signature in " + method.DeclaringType.FullName + "." + method.Name);
  66. }
  67. private MethodInfo beforeSerialize, afterSerialize, beforeDeserialize, afterDeserialize;
  68. /// <summary>Called before serializing an instance</summary>
  69. public MethodInfo BeforeSerialize
  70. {
  71. get { return beforeSerialize; }
  72. set { beforeSerialize = SanityCheckCallback(metaType.Model, value); }
  73. }
  74. /// <summary>Called before deserializing an instance</summary>
  75. public MethodInfo BeforeDeserialize
  76. {
  77. get { return beforeDeserialize; }
  78. set { beforeDeserialize = SanityCheckCallback(metaType.Model, value); }
  79. }
  80. /// <summary>Called after serializing an instance</summary>
  81. public MethodInfo AfterSerialize
  82. {
  83. get { return afterSerialize; }
  84. set { afterSerialize = SanityCheckCallback(metaType.Model, value); }
  85. }
  86. /// <summary>Called after deserializing an instance</summary>
  87. public MethodInfo AfterDeserialize
  88. {
  89. get { return afterDeserialize; }
  90. set { afterDeserialize = SanityCheckCallback(metaType.Model, value); }
  91. }
  92. /// <summary>
  93. /// True if any callback is set, else False
  94. /// </summary>
  95. public bool NonTrivial
  96. {
  97. get
  98. {
  99. return beforeSerialize != null || beforeDeserialize != null
  100. || afterSerialize != null || afterDeserialize != null;
  101. }
  102. }
  103. }
  104. }
  105. #endif