#if !NO_RUNTIME
using System;
#if FEAT_IKVM
using Type = IKVM.Reflection.Type;
using IKVM.Reflection;
#else
using System.Reflection;
#endif
namespace ProtoBuf.Meta
{
///
/// Represents the set of serialization callbacks to be used when serializing/deserializing a type.
///
public class CallbackSet
{
private readonly MetaType metaType;
internal CallbackSet(MetaType metaType)
{
if (metaType == null) throw new ArgumentNullException("metaType");
this.metaType = metaType;
}
internal MethodInfo this[TypeModel.CallbackType callbackType]
{
get
{
switch (callbackType)
{
case TypeModel.CallbackType.BeforeSerialize: return beforeSerialize;
case TypeModel.CallbackType.AfterSerialize: return afterSerialize;
case TypeModel.CallbackType.BeforeDeserialize: return beforeDeserialize;
case TypeModel.CallbackType.AfterDeserialize: return afterDeserialize;
default: throw new ArgumentException("Callback type not supported: " + callbackType.ToString(), "callbackType");
}
}
}
internal static bool CheckCallbackParameters(TypeModel model, MethodInfo method)
{
ParameterInfo[] args = method.GetParameters();
for (int i = 0; i < args.Length; i++)
{
Type paramType = args[i].ParameterType;
if(paramType == model.MapType(typeof(SerializationContext))) {}
else if(paramType == model.MapType(typeof(System.Type))) {}
#if PLAT_BINARYFORMATTER
else if(paramType == model.MapType(typeof(System.Runtime.Serialization.StreamingContext))) {}
#endif
else return false;
}
return true;
}
private MethodInfo SanityCheckCallback(TypeModel model, MethodInfo callback)
{
metaType.ThrowIfFrozen();
if (callback == null) return callback; // fine
if (callback.IsStatic) throw new ArgumentException("Callbacks cannot be static", "callback");
if (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);
}
private MethodInfo beforeSerialize, afterSerialize, beforeDeserialize, afterDeserialize;
/// Called before serializing an instance
public MethodInfo BeforeSerialize
{
get { return beforeSerialize; }
set { beforeSerialize = SanityCheckCallback(metaType.Model, value); }
}
/// Called before deserializing an instance
public MethodInfo BeforeDeserialize
{
get { return beforeDeserialize; }
set { beforeDeserialize = SanityCheckCallback(metaType.Model, value); }
}
/// Called after serializing an instance
public MethodInfo AfterSerialize
{
get { return afterSerialize; }
set { afterSerialize = SanityCheckCallback(metaType.Model, value); }
}
/// Called after deserializing an instance
public MethodInfo AfterDeserialize
{
get { return afterDeserialize; }
set { afterDeserialize = SanityCheckCallback(metaType.Model, value); }
}
///
/// True if any callback is set, else False
///
public bool NonTrivial
{
get
{
return beforeSerialize != null || beforeDeserialize != null
|| afterSerialize != null || afterDeserialize != null;
}
}
}
}
#endif