Cra*_*des 18 c# serialization compact-framework exception
我想写一个MS Message Queue的异常.当我尝试它时,我得到一个例外.所以我尝试使用仍然引发异常的XmlSerializer来简化它,但它给了我更多信息:
{"反映类型'System.Exception'时出错."}
与InnerException:
{"无法序列化System.Collections.IDictionary类型的成员System.Exception.Data,因为它实现了IDictionary."}
示例代码:
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();
Run Code Online (Sandbox Code Playgroud)
编辑:我尽量保持这个简单,但我可能已经过头了.我想要整个位,堆栈跟踪,消息,自定义异常类型和自定义异常属性.我甚至可能想再次抛出异常.
Cra*_*des 10
我正在看杰森杰克逊的答案,但即使System.Exception实现了ISerializable,我也没有理由对我有这个问题.所以我通过将异常包装在使用BinaryFormatter的类中来绕过XmlSerializer.当MS消息队列对象的XmlSerialization全部启动时,它将看到一个带有公共字节数组的类.
这是我想出的:
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();
}
}
Run Code Online (Sandbox Code Playgroud)
第一次测试工作得很好,但我仍然担心自定义异常.所以我把我自己的自定义异常抛在了一起.然后我在一张空白表格上放了一个按钮.这是代码:
[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;
}
Run Code Online (Sandbox Code Playgroud)
虽然看起来我查找的所有其他异常类型都标有SerializableAttribute,但我将不得不小心未使用SerializableAttribute标记的自定义异常.
编辑:超越自己.我没有意识到在CF上没有实现BinaryFormatter.
编辑:上面的代码片段在桌面项目中.在CF版本中,WrappedException基本上看起来与我只需要实现我自己的BinaryFormater相同,但我对这个建议非常开放.
我认为你基本上有两个选择:
在跨进程边界进行远程处理或与系统交互时,序列化异常是一项常见任务.不要听别人说的话; 他们可能从未写过远程库.
我之前通过创建自定义的基本异常类来检测远程执行操作.我遇到的问题是System.Exception不容易序列化,所以我不得不继承它.我处理这个问题的方法是创建自己的异常序列化(通过ISerializable),并在自定义异常中包装任何System.Exception.
在整个服务器代码中,您应该使用自定义异常,这些都可以基于您的可序列化基本类型.这项工作并不多,您将很快建立一个共同的例外库.
您写入队列(并从中读取)的层应该执行所有异常序列化/水合作用.你可能会考虑这样的事情:
public class WireObject<T, E>
{
public T Payload{get;set;}
public E Exception{get;set;}
}
Run Code Online (Sandbox Code Playgroud)
与队列通信的服务器和客户端层将包装您在Payload中发送的对象,或附加异常(如果有).当从队列中消耗数据时,客户端层可以检查异常并在存在时重新抛出异常,否则将数据提交给您.
这是我之前写过的一个非常简单的版本,以及我看到别人写的内容.祝你的项目好运.