在 C# 中,如何序列化 System.Exception?(.Net CF 2.0)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/390051/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
In C#, how can I serialize System.Exception? (.Net CF 2.0)
提问by CrashCodes
I want to write an Exception to an MS Message Queue. When I attempt it I get an exception. So I tried simplifying it by using the XmlSerializer which still raises an exception, but it gave me a bit more info:
我想将异常写入 MS 消息队列。当我尝试它时,我得到了一个例外。所以我尝试通过使用 XmlSerializer 来简化它,但它仍然引发异常,但它给了我更多信息:
{"There was an error reflecting type 'System.Exception'."}
{"有一个错误反映类型'System.Exception'。"}
with InnerException:
带有内部异常:
{"Cannot serialize member System.Exception.Data of type System.Collections.IDictionary, because it implements IDictionary."}
{"无法序列化 System.Collections.IDictionary 类型的成员 System.Exception.Data,因为它实现了 IDictionary。"}
Sample Code:
示例代码:
Exception e = new Exception("Hello, world!");
MemoryStream stream = new MemoryStream();
XmlSerializer x = new XmlSerializer(e.GetType()); // Exception raised on this line
x.Serialize(stream, e);
stream.Close();
EDIT: I tried to keep this a simple as possible, but I may have overdone it. I want the whole bit, stack trace, message, custom exception type, and custom exception properties. I may even want to throw the exception again.
编辑:我试图保持这个尽可能简单,但我可能做得过头了。我想要整个位、堆栈跟踪、消息、自定义异常类型和自定义异常属性。我什至可能想再次抛出异常。
采纳答案by Kon
I think you basically have two options:
我认为您基本上有两种选择:
- Do your own manual serialization (probably do NOT want to do that). XML serialization will surely not work due to the exact message you get in the inner exception.
- Create your own custom (serializable) exception class, inject data from the thrown Exception into your custom one and serialize that.
- 做你自己的手动序列化(可能不想这样做)。由于您在内部异常中获得的确切消息,XML 序列化肯定不起作用。
- 创建您自己的自定义(可序列化)异常类,将抛出的异常中的数据注入您的自定义异常类并对其进行序列化。
回答by Otávio Décio
Why? Are you instantiating an Exception upon retrieving it from the message queue? If not, just send the exception message (as string)...
为什么?您是否在从消息队列中检索异常时实例化异常?如果没有,只需发送异常消息(作为字符串)...
回答by Ed S.
You cannot serialize a dictionary to xml. Do what the other guy said and send the message, that is the important bit anyway.
您不能将字典序列化为 xml。照其他人说的做并发送消息,无论如何这是重要的一点。
回答by Jason Hymanson
Commentary:
评论:
Serializing exceptions is a common task when remoting or interacting with systems across process boundaries. Don't listen to anyone who says otherwise; they have probably never written a remoting library.
在跨进程边界远程处理或与系统交互时,序列化异常是一项常见任务。不要听任何人说相反的话;他们可能从未编写过远程库。
Solution:
解决方案:
I have plumbed remoting to do this before by creating a custom, base exception class. The problem I ran into was that System.Exception does not serialize easily so I had to inherit from it. The way I handled this was by creating my own exceptions that did serialize (through ISerializable), and wrapped any System.Exception in a custom exception.
我之前已经通过创建自定义的基本异常类来进行远程处理来做到这一点。我遇到的问题是 System.Exception 不容易序列化,所以我不得不继承它。我处理这个问题的方法是创建我自己的异常序列化(通过 ISerializable),并将任何 System.Exception 包装在自定义异常中。
Throughout your server code you should use custom exceptions anyway, and these can all be based on your serializable base type. It is not much work, and you will quickly build up a common library of exceptions to through.
在整个服务器代码中,无论如何都应该使用自定义异常,这些都可以基于您的可序列化基本类型。工作量不大,您将很快建立一个通用的异常库。
The layer you write out to the queue (and read from) should do all the exception serialization/hydration. You might consider something like this:
您写入队列(并从中读取)的层应该执行所有异常序列化/水化。你可能会考虑这样的事情:
public class WireObject<T, E>
{
public T Payload{get;set;}
public E Exception{get;set;}
}
The server and client layers that talk to your queue will wrap the object you are sending in the Payload, or attach an exception (if any). When the data is consumed from the queue, the client layer can check for an exception and re-throw it if present, else hand you your data.
与您的队列通信的服务器层和客户端层会将您发送的对象包装在有效负载中,或者附加一个异常(如果有)。当队列中的数据被消耗时,客户端层可以检查异常并在存在时重新抛出它,否则将数据交给你。
This is a very simple version of what I have written before, and what I have seen others write. Good luck on your project.
这是我之前写的一个非常简单的版本,以及我看到其他人写的。祝你的项目好运。
回答by CrashCodes
I was looking at Jason Hymanson's answer, but it didn't make sense to me that I'm having problems with this even though System.Exception implements ISerializable. So I bypassed the XmlSerializer by wrapping the exception in a class that uses a BinaryFormatter instead. When the XmlSerialization of the MS Message Queuing objects kicks in all it will see is a class with a public byte array.
我正在查看 Jason Hymanson 的答案,但即使 System.Exception 实现了 ISerializable,我也遇到了这个问题,这对我来说没有意义。因此,我通过将异常包装在使用 BinaryFormatter 的类中来绕过 XmlSerializer。当 MS 消息队列对象的 XmlSerialization 启动时,它会看到一个具有公共字节数组的类。
Here's what I came up with:
这是我想出的:
public class WrappedException {
public byte[] Data;
public WrappedException() {
}
public WrappedException(Exception e) {
SetException(e);
}
public Exception GetException() {
Exception result;
BinaryFormatter bf = new BinaryFormatter();
MemoryStream stream = new MemoryStream(Data);
result = (Exception)bf.Deserialize(stream);
stream.Close();
return result;
}
public void SetException(Exception e) {
MemoryStream stream = new MemoryStream();
BinaryFormatter bf = new BinaryFormatter();
bf.Serialize(stream, e);
Data = stream.ToArray();
stream.Close();
}
}
The first test worked perfectly, but I was still concerned about custom exceptions. So I tossed together my own custom exception. Then I just dropped a button on a blank form. Here's the code:
第一个测试运行良好,但我仍然担心自定义异常。所以我把我自己的自定义异常扔在一起。然后我只是在空白表格上放了一个按钮。这是代码:
[Serializable]
public class MyException : Exception, ISerializable {
public int ErrorCode = 10;
public MyException(SerializationInfo info, StreamingContext context)
: base(info, context) {
ErrorCode = info.GetInt32("ErrorCode");
}
public MyException(string message)
: base(message) {
}
#region ISerializable Members
void ISerializable.GetObjectData(SerializationInfo info,
StreamingContext context) {
base.GetObjectData(info, context);
info.AddValue("ErrorCode", ErrorCode);
}
#endregion
}
private void button1_Click(object sender, EventArgs e) {
MyException ex = new MyException("Hello, world!");
ex.ErrorCode = 20;
WrappedException reply = new WrappedException(ex);
XmlSerializer x = new XmlSerializer(reply.GetType());
MemoryStream stream = new MemoryStream();
x.Serialize(stream, reply);
stream.Position = 0;
WrappedException reply2 = (WrappedException)x.Deserialize(stream);
MyException ex2 = (MyException)reply2.GetException();
stream.Close();
Text = ex2.ErrorCode.ToString(); // form shows 20
// throw ex2;
}
Although it seemed like all of other exception types that I looked up are marked with the SerializableAttribute, I'm going to have to be careful about custom exceptions that are not marked with the SerializableAttribute.
尽管我查找的所有其他异常类型似乎都标有 SerializableAttribute,但我必须小心未标有 SerializableAttribute 的自定义异常。
EDIT: Getting ahead of myself. I didn't realize that BinaryFormatter is not implemented on CF.
编辑:超越自己。我没有意识到 BinaryFormatter 没有在 CF 上实现。
EDIT: Above code snippets were in a desktop project. In the CF version, the WrappedException will basically look the same I justneed to implement my own BinaryFormater, but I'm very open to suggestions on that one.
编辑:上面的代码片段在一个桌面项目中。在 CF 版本中,WrappedException 基本上看起来相同,我只需要实现我自己的 BinaryFormater,但我非常愿意接受有关该建议的建议。
回答by configurator
Well, XML serialization is limited in its uses. It cannot, for example, serialize this specific scenario. For exact serialization and deserialization of Exceptions you would have to use a BinaryFormatter
, which would work as long as your own exceptions are marked [Serializable]
. All .Net exceptions are marked with this SerializableAttribute
, meaning they can be serialized with the BinaryFormatter
.
嗯,XML 序列化的用途是有限的。例如,它不能序列化此特定场景。对于 Exceptions 的精确序列化和反序列化,您必须使用 a BinaryFormatter
,只要您自己的异常被标记,它就可以工作[Serializable]
。所有 .Net 异常都标有 this SerializableAttribute
,这意味着它们可以使用BinaryFormatter
.
There's a gotcha there you must look out for, though.
If your exception is not serializable it will obviously fail. But it will also fail when your exception contains a field that is not serializable. You should watch out to make sure that isn't possible in your custom exceptions.
不过,您必须注意一个问题。
如果您的异常不可序列化,它显然会失败。但是当您的异常包含不可序列化的字段时,它也会失败。您应该注意确保这在您的自定义异常中是不可能的。