130 lines
2.9 KiB
C#
130 lines
2.9 KiB
C#
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);
|
||
|
|
}
|
||
|
|
}
|