C# 序列化代码导致未处理的异常
我试图创建一个可以将类库序列化和反序列化为AutoCAD图形的代码。这个问题与AutoCAD没有什么关系,只是我无法用常规方法调试它的原因。我从开始这个项目,并成功地让他的代码运行。无论他的代码是如何构造的,它都需要我让我的所有类继承自他的baseobject。由于这显然是一种代码味道,我知道我需要创建一个接口。下面是我最终得到的代码 第一部分是负责在AutoCAD图形中进行序列化的代码 第二部分是实现自定义序列化接口的类的示例C# 序列化代码导致未处理的异常,c#,serialization,autocad,unhandled-exception,autocad-plugin,C#,Serialization,Autocad,Unhandled Exception,Autocad Plugin,我试图创建一个可以将类库序列化和反序列化为AutoCAD图形的代码。这个问题与AutoCAD没有什么关系,只是我无法用常规方法调试它的原因。我从开始这个项目,并成功地让他的代码运行。无论他的代码是如何构造的,它都需要我让我的所有类继承自他的baseobject。由于这显然是一种代码味道,我知道我需要创建一个接口。下面是我最终得到的代码 第一部分是负责在AutoCAD图形中进行序列化的代码 第二部分是实现自定义序列化接口的类的示例 public class Commands { publi
public class Commands
{
public class MyUtil
{
const int kMaxChunkSize = 127;
public ResultBuffer StreamToResBuf(MemoryStream ms, string appName)
{
ResultBuffer resBuf = new ResultBuffer(new TypedValue((int)DxfCode.ExtendedDataRegAppName, appName));
for (int i = 0; i < ms.Length; i += kMaxChunkSize)
{
int length = (int)Math.Min(ms.Length - i, kMaxChunkSize);
byte[] datachunk = new byte[length];
ms.Read(datachunk, 0, length);
resBuf.Add(new TypedValue((int)DxfCode.ExtendedDataBinaryChunk, datachunk));
}
return resBuf;
}
public MemoryStream ResBufToStream(ResultBuffer resBuf)
{
MemoryStream ms = new MemoryStream();
TypedValue[] values = resBuf.AsArray();
// Start from 1 to skip application name
for (int i = 1; i < values.Length; i++)
{
byte[] datachunk = (byte[])values[i].Value;
ms.Write(datachunk, 0, datachunk.Length);
}
ms.Position = 0;
return ms;
}
public void NewFromEntity(IClearspanSerializable objectToSave, Entity ent)
{
using (ResultBuffer resBuf = ent.GetXDataForApplication("Member"))
{
BinaryFormatter bf = new BinaryFormatter();
bf.Binder = new MyBinder();
MemoryStream ms = this.ResBufToStream(resBuf);
objectToSave.SetObjectData(bf.Deserialize(ms));
}
}
public void SaveToEntity(IClearspanSerializable objectToSave, Entity ent)
{
// Make sure application name is registered
// If we were to save the ResultBuffer to an Xrecord.Data,
// then we would not need to have a registered application name
Transaction tr = ent.Database.TransactionManager.TopTransaction;
RegAppTable regTable = (RegAppTable)tr.GetObject(ent.Database.RegAppTableId, OpenMode.ForWrite);
if (!regTable.Has("Member"))
{
RegAppTableRecord app = new RegAppTableRecord();
app.Name = "Member";
regTable.Add(app);
tr.AddNewlyCreatedDBObject(app, true);
}
BinaryFormatter bf = new BinaryFormatter();
MemoryStream ms = new MemoryStream();
bf.Serialize(ms, objectToSave);
ms.Position = 0;
ent.XData = this.StreamToResBuf(ms, "Member");;
}
}
public sealed class MyBinder : SerializationBinder
{
public override Type BindToType(string assemblyName, string typeName)
{
return Type.GetType(string.Format("{0}, {1}",
typeName, assemblyName));
}
}
[CommandMethod("SaveClassToEntityXData", CommandFlags.Modal)]
public void SaveClassToEntityXData(IClearspanSerializable objectToSerialize)
{
Database db = Application.DocumentManager.MdiActiveDocument.Database;
Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
PromptEntityResult per = ed.GetEntity("Select entity to save class to:\n");
if (per.Status != PromptStatus.OK)
return;
MyUtil util = new MyUtil();
// Save it to the document
using (Transaction tr = db.TransactionManager.StartTransaction())
{
Entity ent = (Entity)tr.GetObject(per.ObjectId, OpenMode.ForWrite);
util.SaveToEntity(objectToSerialize, ent);
tr.Commit();
}
// Write some info about the results
//ed.WriteMessage("Content of MyClass we serialized:\n {0} \n", mc.ToString());
}
[CommandMethod("GetClassFromEntityXData", CommandFlags.Modal)]
public void GetClassFromEntityXData(IClearspanSerializable objectToRestore)
{
Database db = Application.DocumentManager.MdiActiveDocument.Database;
Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
MyUtil util = new MyUtil();
PromptEntityResult per = ed.GetEntity("Select entity to get class from:\n");
if (per.Status != PromptStatus.OK)
return;
// Get back the class
using (Transaction tr = db.TransactionManager.StartTransaction())
{
Entity ent = (Entity)tr.GetObject(per.ObjectId, OpenMode.ForRead);
util.NewFromEntity(objectToRestore, ent);
tr.Commit();
}
}
}
当我尝试在AutoCAD中运行代码时,得到的只是此错误。这让我相信在初始化类时有一个简单的bug。我的断点中没有一个被击中
我应该如何调试它?我在哪里搞砸了初始化
[编辑]-以下是“详细信息”中的内容:
黑暗中拍摄:您需要一个默认构造函数,因为其他人构造了您的对象:
public MattMember()
{
}
或者像这样的特殊反序列化构造函数:
protected MattMember(SerializationInfo info, StreamingContext context)
{
// Set object data
}
可能您的接口还需要从ISerializable继承
at System.Delegate.CreateDelegate(Type type, Object firstArgument, MethodInfo method, Boolean throwOnBindFailure)
at System.Delegate.CreateDelegate(Type type, Object firstArgument, MethodInfo method)
at Autodesk.AutoCAD.Runtime.CommandClass.InvokeWorker(MethodInfo mi, Object commandObject, Boolean bLispFunction)
正确解释堆栈跟踪非常重要。你发布的代码都没有涉及,它从来没有开始过。当AutoCAD尝试调用命令处理程序时,此操作失败:
[CommandMethod("GetClassFromEntityXData", CommandFlags.Modal)]
public void GetClassFromEntityXData(IClearspanSerializable objectToRestore)
// etc..
AutoCAD不会给您那个objectToRestore参数,它不知道您的接口。这就是异常的意思,它不能将委托绑定到具有神秘参数的方法。请注意,从中启动的示例代码如何使用不带参数的方法。以及它如何使用Editor.GetEntity()允许用户拾取图形实体。我假设您需要类似的方案,但我对AutoCAD脚本了解不够
System.ArgumentException:无法绑定到目标方法,因为其
签名或安全透明度与
委托类型
我的理解是,您的接口的“GetObjectData”方法与ISerializable方法冲突,在BinnaryFormatter kitchen的某个地方
只需重构MyUtil中的所有转换函数(StreamToResBuf、ResBufToStream…),就可以序列化/反序列化任何标记有[Serializable]属性的类。
您的虚拟类应该如下所示(集合和基元类型是自动序列化的,仅在需要时实现ISerializable): 最后是你的命令:
[CommandMethod("GetClassFromEntityXData", CommandFlags.Modal)]
//Updated return type here but don't know if it is correct with AutoCAD
public object GetClassFromEntityXData()
{
Database db = Application.DocumentManager.MdiActiveDocument.Database;
Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
object objectToRestore;
MyUtil util = new MyUtil();
PromptEntityResult per = ed.GetEntity("Select entity to get class from:\n");
if (per.Status != PromptStatus.OK)
return;
// Get back the class
using (Transaction tr = db.TransactionManager.StartTransaction())
{
Entity ent = (Entity)tr.GetObject(per.ObjectId, OpenMode.ForRead);
//Cast to your IClearspan interface here, or use Reflection
// to determine deserialized object's Type
objectToRestore = util.NewFromEntity(ent);
tr.Commit();
}
return objectToRestore;
}
实现该命令的函数不能接受参数,但在命令实现内部,可以使用命令行输入函数(如GetString()、GetInteger()等)接受参数,这些函数可以在编辑器类下找到
从中,请先单击详细信息按钮,然后将详细信息粘贴到帖子中。我想知道为什么这个问题会得到5票以上……这是什么版本/位的AutoCAD?这是32位Windows 7机器上的AutoCAD 2015
at System.Delegate.CreateDelegate(Type type, Object firstArgument, MethodInfo method, Boolean throwOnBindFailure)
at System.Delegate.CreateDelegate(Type type, Object firstArgument, MethodInfo method)
at Autodesk.AutoCAD.Runtime.CommandClass.InvokeWorker(MethodInfo mi, Object commandObject, Boolean bLispFunction)
[CommandMethod("GetClassFromEntityXData", CommandFlags.Modal)]
public void GetClassFromEntityXData(IClearspanSerializable objectToRestore)
// etc..
[Serializable]
public class MattMember
{
public string Name;
List<int> MattsInts;
}
public object NewFromEntity(Entity ent)
{
using (ResultBuffer resBuf = ent.GetXDataForApplication("Member"))
{
BinaryFormatter bf = new BinaryFormatter();
bf.Binder = new MyBinder();
MemoryStream ms = this.ResBufToStream(resBuf);
return bf.Deserialize(ms);
}
}
[CommandMethod("GetClassFromEntityXData", CommandFlags.Modal)]
//Updated return type here but don't know if it is correct with AutoCAD
public object GetClassFromEntityXData()
{
Database db = Application.DocumentManager.MdiActiveDocument.Database;
Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
object objectToRestore;
MyUtil util = new MyUtil();
PromptEntityResult per = ed.GetEntity("Select entity to get class from:\n");
if (per.Status != PromptStatus.OK)
return;
// Get back the class
using (Transaction tr = db.TransactionManager.StartTransaction())
{
Entity ent = (Entity)tr.GetObject(per.ObjectId, OpenMode.ForRead);
//Cast to your IClearspan interface here, or use Reflection
// to determine deserialized object's Type
objectToRestore = util.NewFromEntity(ent);
tr.Commit();
}
return objectToRestore;
}
[CommandMethod("SaveClassToEntityXData", CommandFlags.Modal)]
public void SaveClassToEntityXData(IClearspanSerializable objectToSerialize)