即使使用了[field:NonSerialized],仍然出现Serializationexception。

3

我有一个运行着的IPC服务器,其接口非常简单,目前工作得相当不错。接口本身非常简单,仅由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类的序列化方法:

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

很难弄清楚SingleTone是什么意思。它是Singleton吗?你真的需要发布异常详细信息,包括堆栈跟踪。 - Hans Passant
我在我的第一篇帖子中添加了异常堆栈 :) - Fge
2个回答

2

在尝试了各种方法告诉序列化程序不要序列化我的事件但它们仍然被序列化后,我换一种方式尝试:为我的NetworkHook类提供一个可序列化的类。
所以我创建了一个名为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 搜索,我了解到 MarshalByRefObject 不使用 ISerializable 接口,而是使用自己的接口,因此使所有序列化命令无效。相反,您必须使用代理序列化。 - Fge
很高兴你解决了它,下次我遇到这种情况会记住的 :) - leppie

1

event 只是更复杂结构的语法糖。

你需要将其分解才能使其正常工作。

它等同于:

private EventHandler eventField;

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

为了使序列化正常工作,您需要将NonSerialized属性应用于eventField字段。


@Fge:我怀疑这与MarshalByRefObject有关。 - leppie

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接