2010-10-15 6 views
3

J'ai un serveur IPC fonctionnant avec une interface très simple qui fonctionne assez bien pour le moment. L'interface elle-même est vraiment simple et ne comporte que 4 méthodes. (RemoteCall méthode est Singletone):Serializationexception même avec [field: NonSerialized]

[Serializable] 
public class NetworkHook : MarshalByRefObject 
{ 
    public void onIsInstalled(int pid, MessageDirection direction) 
    { 
    } 

    public void onDataRecieved(int pid, MessageDirection direction, byte[][] data) 
    { 
    } 

    public void onException(int pid, MessageDirection direction, Exception exception) 
    { 
    } 

    public void onPing(int pid, MessageDirection direction) 
    { 
    } 
} 

Troubles commencé quand j'ai commencé à ajouter des événements à cette classe (si une partie du serveur peut souscrire aux messages entrants, la méthode d'appel à distance est Singletone pour garder les EventListeners). Comme le NetworkHook est sérialisable, j'ai commencé à ajouter des balises [field: NonSerialzied] à mes événements. Cela devrait être bien que je ne ai pas besoin des clients d'être au courant des événements-auditeurs (ou ne les veulent être du tout) afin de les perdre est ok:

[field: NonSerialized] 
public event EventHandler<InstalledEventArgs> Test; 

Quoi qu'il en soit, j'ai toujours eu ce l'erreur et essayé une autre approche avec un eventhandler personnalisé cette fois:

public delegate void HookInstalledEventHandler(object sender, HookInstalledEventArgs args); 

[field: NonSerialized] 
public event HookInstalledEventHandler Test; 

et encore une fois - je reçois toujours l'exception lors de l'ajout d'auditeurs à l'événement. Donc, j'ai essayé de remplacer la méthode de sérialisation de la NetworkHook Classe:

public virtual void GetObjectData(SerializationInfo info, StreamingContext context) 
{ 

} 

Comme je ne dispose d'aucune variable que je dois enregistrer c'est assez simple. Mais encore une fois - je reçois une exception. Maintenant, je n'ai plus d'idées sur ce que je pourrais faire pour empêcher cette exception, ou qu'est-ce que je fais de mal ici (rendre les événements statiques est un choix que je ne veux vraiment pas faire)?

L'exception je reçois:

System.Runtime.Serialization.SerializationException wurde nicht behandelt. 
    Message="Der Typ \"SimpleHookGUI.CommandLineReporter\" in Assembly \"SimpleHookGUI, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null\" ist nicht als serialisierbar gekennzeichnet." 
    Source="mscorlib" 
    StackTrace: 
    Server stack trace: 
     bei System.Runtime.Serialization.FormatterServices.InternalGetSerializableMembers(RuntimeType type) 
     bei System.Runtime.Serialization.FormatterServices.GetSerializableMembers(Type type, StreamingContext context) 
     bei System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.InitMemberInfo() 
     bei System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.InitSerialize(Object obj, ISurrogateSelector surrogateSelector, StreamingContext context, SerObjectInfoInit serObjectInfoInit, IFormatterConverter converter, ObjectWriter objectWriter) 
     bei System.Runtime.Serialization.Formatters.Binary.ObjectWriter.Write(WriteObjectInfo objectInfo, NameInfo memberNameInfo, NameInfo typeNameInfo) 
     bei System.Runtime.Serialization.Formatters.Binary.ObjectWriter.Serialize(Object graph, Header[] inHeaders, __BinaryWriter serWriter, Boolean fCheck) 
     bei System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize(Stream serializationStream, Object graph, Header[] headers, Boolean fCheck) 
     bei System.Runtime.Remoting.Channels.BinaryClientFormatterSink.SerializeMessage(IMessage msg, ITransportHeaders& headers, Stream& stream) 
     bei System.Runtime.Remoting.Channels.BinaryClientFormatterSink.SyncProcessMessage(IMessage msg) 
    Exception rethrown at [0]: 
     bei System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg) 
     bei System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type) 
     bei HookManager.NetworkObserver.NetworkHook.add_Test(HookInstalledEventHandler value) 
     bei SimpleHookGUI.Program.Main() in xxx\Program.cs:Zeile 24. 
     bei System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args) 
     bei Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() 
     bei System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) 
     bei System.Threading.ThreadHelper.ThreadStart() 
    InnerException: 

J'ai essayé pour la première réponse:

[field: NonSerialized] 
private event EventHandler<HookInstalledEventArgs> test; 

public event EventHandler<HookInstalledEventArgs> Test 
{ 
    add { this.test = (EventHandler<HookInstalledEventArgs>) Delegate.Combine(this.test, value); } 
    remove { this.test = (EventHandler<HookInstalledEventArgs>) Delegate.Remove(this.test, value); } 
} 
+0

Quelle est l'exception exacte? –

+0

Difficile de comprendre ce que signifie SingleTone. Est-ce Singleton? Vous avez vraiment besoin de publier les détails de l'exception, la trace de la pile incluse. –

+0

J'ai ajouté la pile d'exception à mon premier message :) – Fge

Répondre

1

event est juste pour le sucre construction plus complexe.

Vous devez le décomposer pour que cela fonctionne.

Il est équivalent à:

private EventHandler eventField; 

public event EventHandler SomeEvent 
{ 
    add { eventfield = Delegate.Combine(eventfield, value); } 
    remove { eventfield = Delegate.Remove(eventfield, value); } 
} 

Pour sérialisation à travailler, vous devez appliquer l'attribut NonSerialized au champ eventField.

+0

Je l'ai essayé de cette façon aussi (même exception): – Fge

+0

@Fge: Je suppose que cela a quelque chose à voir avec 'MarshalByRefObject'. – leppie

2

Après avoir essayé de toute façon de dire à la sérialisation de ne pas sérialiser mes événements mais qu'ils continuaient à être sérialisés, je l'ai essayé dans le sens inverse - donnez à ma classe NetworkHook ce qu'elle veut, une classe sérialisable.
Je créé une nouvelle classe de test appelé NetworkListener qui est sérialisable mais ne sérialise pas les événements:

[Serializable] 
public class NetworkListener 
{ 
    private static EventHandler<HookInstalledEventArgs> hookInstalled; 

    public event EventHandler<HookInstalledEventArgs> HookInstalled 
    { 
     add { hookInstalled = (EventHandler<HookInstalledEventArgs>) Delegate.Combine(hookInstalled, value); } 
     remove { hookInstalled = (EventHandler<HookInstalledEventArgs>) Delegate.Remove(hookInstalled, value); } 
    } 

    public void onHookInstalled(Object sender, HookInstalledEventArgs args) 
    { 
     EventHandler<HookInstalledEventArgs> handler = hookInstalled; 
     if (handler != null) 
     { 
      handler(this, args); 
     } 
    } 
} 

Cette classe peut souscrire à mon NetworkHook: MarshalByRefObject sans lancer une exception. Je pense que c'est juste une solution de contournement sale avec cet événement statique là-bas qui n'a pas de statique à l'extérieur (à côté c'est juste une autre classe pour passer des événements). Mais je ne peux pas le rendre privé seulement et le marquer avec [field: NonSerialized()] car il perd tout simplement les callbacks alors. donc au moins je voulais me débarrasser de cette classe supplémentaire et comprennent que-contournement de l'événement dans ma classe d'origine:

public class NetworkHook : MarshalByRefObject 
{ 
    private static EventHandler<HookInstalledEventArgs> hookInstalled; 

    public event EventHandler<HookInstalledEventArgs> HookInstalled 
    { 
     add { hookInstalled = (EventHandler<HookInstalledEventArgs>) Delegate.Combine(hookInstalled, value); } 
     remove { hookInstalled = (EventHandler<HookInstalledEventArgs>) Delegate.Remove(hookInstalled, value); } 
    } 
    // .... 
} 

Et par surprise - je reçois mon exception à nouveau. J'ai l'impression que le MarshalByRefObject contourne complètement mes commandes de sérialisation ... d'une façon ou d'une autre. Eh bien - c'est une très mauvaise solution et je vais devoir réécrire d'autres classes pour y intégrer - mais pour la première fois en quelques heures - ça marche du tout. Si quelqu'un a une meilleure solution, j'adorerais faire un autre essai :) Tant que je m'en tiendrai à ma classe d'origine appelant un «proxy d'événement» qui délègue les événements réels.

+1

Après quelques msdn-digging, j'ai appris que MarshalByRefObject n'utilisait pas l'interface ISerializable mais qu'il était propre, ce qui rendait inutiles toutes les commandes de sérialisation. Au lieu de cela, vous devez utiliser la sérialisation de substitution. – Fge

+0

Je suis content que vous l'ayez trié, je me souviendrai de la prochaine fois que je serai confronté à ça :) – leppie

Questions connexes