如何序列化对象具有从Action创建的委托的对象?

时间:2016-07-05 00:55:18

标签: c# serialization

如何序列化对象具有从Delegate创建的Action的对象,以便我可以反序列化对象并且Delegate仍在订阅?

这是类代码:

[Serializable]
public class TestClass
{
    public event EventHandler<EventArgs> refresh;
    public void AddHandlerForAction()
    {
        var methodInfo = this.GetType().GetMethod("RefreshMethodNoParamaters");
        Action action = (Action)Delegate.CreateDelegate(typeof(Action), this, methodInfo);

        var eventInfo = this.GetType().GetEvent("refresh");

        var handlerType = eventInfo.EventHandlerType;
        var eventParams = handlerType.GetMethod("Invoke").GetParameters();

        var parameters = eventParams.Select(p => Expression.Parameter(p.ParameterType, "x"));
        var body = Expression.Call(Expression.Constant(action), action.GetType().GetMethod("Invoke"));
        var lambda = Expression.Lambda(body, parameters.ToArray());
        Delegate d = Delegate.CreateDelegate(handlerType, lambda.Compile(), "Invoke", false);

        eventInfo.AddEventHandler(this, d);
    }
    public virtual object Clone()
    {
        Type type = this.GetType();
        if (!type.IsSerializable)
        {
            throw new ArgumentException("The type must be serializable.", "source");
        }

        if (Object.ReferenceEquals(this, null))
        {
            return this.GetType().GetMethod("GetDefaultGeneric").MakeGenericMethod(type).Invoke(this, null);
        }
        using (MemoryStream stream = new MemoryStream())
        {
            BinaryFormatter formatter = new BinaryFormatter();
            formatter.Serialize(stream, this);
            stream.Position = 0;
            var clone = Convert.ChangeType(formatter.Deserialize(stream), type);
            return clone;
        }
    }
    public void RaiseEvent()
    {
        EventHandler<EventArgs> eventHandler = refresh;
        if (eventHandler != null)
        {
            eventHandler(this, new EventArgs());
        }
    }
    public void RefreshMethodNoParamaters()
    {

    }
}

以下是执行例外的代码:

var testClass = new TestClass();
testClass.AddHandlerForAction();
testClass.RaiseEvent();

var clone = testClass.Clone();

此代码行发生异常:

formatter.Serialize(stream, this);

以下是例外:

  

未处理的类型异常   发生'System.Runtime.Serialization.SerializationException'   mscorlib.dll中

     

其他信息:无法通过非托管序列化代理   委托之外的函数指针,动态方法或方法   创作者的集会。

代码的目标是订阅Event,其中引发Event时调用的方法没有参数。

1 个答案:

答案 0 :(得分:2)

如果您只想序列化该类,可以使用[NonSerialized]属性。但是你需要使用属性target(field):

[field: NonSerialized]
public event EventHandler<EventArgs> refresh;

以下是attribute specification

的更多信息

编辑:

如果您需要保留附加事件(这适用于您的示例,但不适用于长期存储),您可以在克隆函数中填充事件处理程序:

public virtual object Clone()
{
    //...
    var clone = Convert.ChangeType(formatter.Deserialize(stream), type);

    (clone as TestClass).refresh = this.refresh;

    return clone;    
}

但是对于我的偏好,这是一种非常黑客的方式......