2016-07-05 5 views
1

オブジェクトをActionから作成したDelegateオブジェクトをシリアル化すると、オブジェクトを逆シリアル化でき、Delegateはまだサブスクリプションされていますか?ここオブジェクトからアクションから作成されたデリゲートがあるオブジェクトをシリアル化するにはどうすればよいですか?

クラスコードである:

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

var clone = testClass.Clone(); 

例外コード行で発生する:ここ

formatter.Serialize(stream, this); 

ここ

[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() 
    { 

    } 
} 

は例外を実行するコードであります例外は次のとおりです。

タイプ 「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についてEDIT:あなたは(および添付イベントを維持する必要がある場合

これはあなたの例のために動作しますなく、長期保存のために)あなたのクローン機能でイベントハンドラ取り込むことができます。

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

関連する問題