甚至使用[field:NonSerialized]进行序列化异常

时间:2010-10-15 13:17:15

标签: c#

我有一个IPC-Server运行一些非常简单的界面,现在工作得很好。界面本身非常简单,只包含4种方法。 (RemoteCall方法是SingleTone):

[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来保留事件侦听器)。 由于NetworkHook是可序列化的,我开始在我的事件中添加[field:NonSerialzied]标签。这应该没问题,因为我不需要客户端知道事件监听器(或者他们根本不想要这样做)所以丢失它们是可以的:

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

无论如何,我仍然遇到此错误,并尝试使用自定义事件处理程序的另一种方法:

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

[field: NonSerialized]
public event HookInstalledEventHandler Test;

再次 - 在向事件添加侦听器时仍然会出现异常。所以我试图覆盖NetworkHook-Class的序列化方法:

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

2 个答案:

答案 0 :(得分:2)

在我尝试各种方式告诉序列化不要序列化我的事件但是他们继续进行序列化之后我反过来尝试了 - 给我的类NetworkHook它想要的东西,一个可序列化的类。
所以我创建了一个名为NetworkListener的新Test类,它是可序列化的,但不会序列化事件:

[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 :(得分:1)

event对于更复杂的构造而言只是糖。

您需要对其进行分解才能使其正常工作。

相当于:

private EventHandler eventField;

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

要使序列化生效,您需要将NonSerialized属性应用于eventField字段。