using System; using System.Reflection; using System.Runtime.Serialization; namespace ProtoBuf.Meta; public class CallbackSet { private readonly MetaType metaType; private MethodInfo beforeSerialize; private MethodInfo afterSerialize; private MethodInfo beforeDeserialize; private MethodInfo afterDeserialize; internal MethodInfo this[TypeModel.CallbackType callbackType] => callbackType switch { TypeModel.CallbackType.BeforeSerialize => beforeSerialize, TypeModel.CallbackType.AfterSerialize => afterSerialize, TypeModel.CallbackType.BeforeDeserialize => beforeDeserialize, TypeModel.CallbackType.AfterDeserialize => afterDeserialize, _ => throw new ArgumentException("Callback type not supported: " + callbackType, "callbackType"), }; public MethodInfo BeforeSerialize { get { return beforeSerialize; } set { beforeSerialize = SanityCheckCallback(metaType.Model, value); } } public MethodInfo BeforeDeserialize { get { return beforeDeserialize; } set { beforeDeserialize = SanityCheckCallback(metaType.Model, value); } } public MethodInfo AfterSerialize { get { return afterSerialize; } set { afterSerialize = SanityCheckCallback(metaType.Model, value); } } public MethodInfo AfterDeserialize { get { return afterDeserialize; } set { afterDeserialize = SanityCheckCallback(metaType.Model, value); } } public bool NonTrivial { get { if ((object)beforeSerialize == null && (object)beforeDeserialize == null && (object)afterSerialize == null) { return (object)afterDeserialize != null; } return true; } } internal CallbackSet(MetaType metaType) { this.metaType = metaType ?? throw new ArgumentNullException("metaType"); } internal static bool CheckCallbackParameters(TypeModel model, MethodInfo method) { ParameterInfo[] parameters = method.GetParameters(); for (int i = 0; i < parameters.Length; i++) { Type parameterType = parameters[i].ParameterType; if ((object)parameterType != model.MapType(typeof(SerializationContext)) && (object)parameterType != model.MapType(typeof(Type)) && (object)parameterType != model.MapType(typeof(StreamingContext))) { return false; } } return true; } private MethodInfo SanityCheckCallback(TypeModel model, MethodInfo callback) { metaType.ThrowIfFrozen(); if ((object)callback == null) { return callback; } if (callback.IsStatic) { throw new ArgumentException("Callbacks cannot be static", "callback"); } if ((object)callback.ReturnType != model.MapType(typeof(void)) || !CheckCallbackParameters(model, callback)) { throw CreateInvalidCallbackSignature(callback); } return callback; } internal static Exception CreateInvalidCallbackSignature(MethodInfo method) { return new NotSupportedException("Invalid callback signature in " + method.DeclaringType.FullName + "." + method.Name); } }