2010-10-15 2 views
3

У меня есть IPC-сервер, работающий с некоторым действительно простым интерфейсом, который работает вполне нормально. Сам интерфейс очень прост и состоит всего из 4-х методов. (RemoteCall Метод SingleTone):Serializationexception даже с [поле: 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) 
    { 
    } 
} 

Неприятности начались, когда я начал добавлять события к этому классу (так что любая часть сервера может подписаться на входящие сообщения, метод удаленного вызова является SingleTone держать eventlisteners). Поскольку NetworkHook является сериализуемым, я начал добавлять теги [field: NonSerialzied] к моим событиям. Это должно быть хорошо, как мне не нужно клиентов, чтобы быть в курсе событий-слушателей (или же они не хотят быть вообще), поэтому их потеря в порядке:

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

Во всяком случае я все еще получил это ошибки и попробовал другой подход с настраиваемой EventHandler на этот раз:

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

[field: NonSerialized] 
public event HookInstalledEventHandler Test; 

и снова - я все еще получаю исключение при добавлении слушателей к событию. Таким образом, я попытался переопределить метод сериализации NetworkHook-класса:

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

} 

Как у меня нет каких-либо переменных, мне нужно, чтобы сохранить это довольно просто. Но снова - я получаю исключение. Итак, теперь у меня заканчиваются идеи, что я мог бы предотвратить это исключение, или что я делаю неправильно здесь (что делает статичные события выбором, который я действительно не хочу делать)?

Исключение я получаю:

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: 

Я попытался это первый ответ:

[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

Какое точное исключение? –

+0

Трудно понять, что означает SingleTone. Это Синглтон? Вам действительно нужно публиковать данные об исключениях, включая трассировку стека. –

+0

Я добавил стек исключений в свой первый пост :) – Fge

ответ

1

event только сахар для более сложной конструкции.

Для этого необходимо разложить его.

Это эквивалентно:

private EventHandler eventField; 

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

Для сериализации для работы, вам необходимо применить атрибут NonSerialized к eventField полю.

+0

Я тоже пробовал это тоже (такое же исключение): – Fge

+0

@Fge: Я подозреваю, что это имеет какое-то отношение к 'MarshalByRefObject'. – leppie

2

После того, как я попытался всячески рассказать о сериализации, чтобы не сериализовать мои события, но они продолжали сериализоваться, я попробовал это наоборот - дайте классу NetworkHook то, что он хочет, сериализуемый класс.
Так что я создал новый класс Test под названием NetworkListener, который сериализации, но не сериализовать события:

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

Этот класс может подписаться на мой NetworkHook: MarshalByRefObject, не бросать исключение. Я думаю, что на самом деле это всего лишь грязное обходное решение с таким статическим событием, которое не статично статично снаружи (кроме того, это просто еще один класс для передачи событий). Но я не могу сделать его закрытым только и отмечать его полем [field: NonSerialized()], поскольку он просто теряет все обратные вызовы. Так, по крайней мере, я хотел бы избавиться от этого дополнительного класса и включают в себя, что событие-обходной путь в моем оригинальном классе:

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); } 
    } 
    // .... 
} 

И сюрприз - я получу исключение снова. Я вроде как чувствую, что MarshalByRefObject полностью обходит мои команды сериализации ... как-то. Хорошо - это действительно плохое решение, я думаю, и мне придется переписать некоторые другие классы, чтобы вписаться в это, но впервые за часы - это вообще работает. У меня есть лучшее решение, с которым я бы с удовольствием попросил еще одну попытку :) Пока я придерживаюсь своего первоначального класса, называющего «прокси-сервер событий», который делегирует реальные события.

+1

После того, как еще несколько msdn-digging я уничтожил, что MarshalByRefObject не использует интерфейс ISerializable, но он собственный, что делает все команды сериализации бесполезными. Вместо этого вы должны использовать Serrogate Serialization. – Fge

+0

Рад, что вы его отсортировали, я буду помнить, в следующий раз, когда я столкнусь с этим :) – leppie

Смежные вопросы