2016-07-05 18 views
1

如何序列化一個對象,其中的對象具有從Action創建的Delegate,以便我可以反序列化對象並且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升高時調用的方法沒有參數。

+0

避免這樣做,它會回到你的字節:http://stackoverflow.com/a/40780504/66372。這個答案很好地解釋了這個問題,並有一個替代方案的建議:http://stackoverflow.com/a/1133465/66372。 – eglasius

回答

2

如果您只想序列化該類,則可以使用[NonSerialized]屬性。但是,你需要使用屬性目標(場):

[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;  
} 

但對我的偏愛它是一個非常哈克的方式...

+0

對象序列化後,當引發事件時,不會調用該操作。 – user3736648

+0

@ user3736648用可能的解決方案更新了我的答案 – JleruOHeP

相關問題