gpt4 book ai didi

c# - 反序列化 MemoryStream - 意外行为

转载 作者:太空宇宙 更新时间:2023-11-03 14:28:59 26 4
gpt4 key购买 nike

目前我遇到了一个非常令人沮丧的问题。我将尝试抽象问题以使其更容易一些。它必须在一个进程中将我的自定义对象序列化到数据库并在另一个进程中反序列化它。

我有两个组件; AppToDB.dllAppFromDB.dll。我有第三个程序集 - MyCustomObject.dll - 这两个程序集都包含对它的引用。 MyCustomObject.dll 扩展了 MarshalByRefObject

在我的 AppToDB.dll 中,我执行以下代码:

    public bool serializeToDB(MyCustomObject obj)
{
OdbcDataAdapter da = new OdbcDataAdapter();
MemoryStream memStream = new MemoryStream();

try
{
ObjRef marshalledObj = RemotingServices.Marshal((System.MarshalByRefObject)obj);

// Serialize the object; construct the desired formatter
IFormatter oBFormatter = new BinaryFormatter();

// Try to serialize the object
oBFormatter.Serialize(memStream, marshalledObj);

// Create byte array
byte[] serialized = memStream.ToArray();

// Build the query to write to the database
string queryString =
"INSERT INTO MyCustomObject(id, object) VALUES(?, ?)";
OdbcCommand command = new OdbcCommand(queryString, connection);
command.Parameters.AddWithValue("id", 1);
command.Parameters.AddWithValue("object", serialized);

// Write the object byte array to the database
int num = command.ExecuteNonQuery();
}
catch { }
}

AppFromDB.dll 中,我执行这段代码:

    public OCR.Batch deserializeFromDB()
{
MemoryStream memStream = new MemoryStream();

try
{
string queryString = "SELECT object FROM FCBatch";
OdbcCommand command = new OdbcCommand(queryString, connection);
OdbcDataReader reader = command.ExecuteReader(CommandBehavior.SequentialAccess);

// Size of the BLOB buffer.
int bufferSize = 100;
// The BLOB byte[] buffer to be filled by GetBytes.
byte[] outByte = new byte[bufferSize];
// The bytes returned from GetBytes.
long retval;
// The starting position in the BLOB output.
long startIndex = 0;

MemoryStream dbStream = new MemoryStream();

while (reader.Read())
{
// Reset the starting byte for the new BLOB.
startIndex = 0;

// Read bytes into outByte[] and retain the number of bytes returned.
retval = reader.GetBytes(0, startIndex, outByte, 0, bufferSize);

// Continue while there are bytes beyond the size of the buffer.
while (retval == bufferSize)
{
dbStream.Write(outByte, 0, bufferSize);
dbStream.Flush();

// Reposition start index to end of last buffer and fill buffer.
startIndex += bufferSize;
retval = reader.GetBytes(0, startIndex, outByte, 0, bufferSize);
}

// Write the remaining buffer.
dbStream.Write(outByte, 0, (int)retval);
dbStream.Flush();
}
// Close the reader and the connection.
reader.Close();

dbStream.Position = 0;
object temp = oBFormatter.Deserialize(dbStream);
MyCustomObject obj = (MyCustomObject)temp;

return null;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
return null;
}
}

好的,所以在这两段代码中您都可以看到一个 MemoryStream 对象。在第一个 AppToDB 中,它被创建,如果我查看它的内容,它包含 707 个字节。美好的。我将它写入数据库并将其作为 BLOB 保存在那里。现在,在 AppFromDB 中,我检索 BLOB 并将其存储在 byte[] 数组中。我再次将 byte[] 数组写入 MemoryStream,看到我的 MemoryStream 对象包含 707 个字节,所有这些都在适当的位置原本的。看来我转移对象成功了!

现在问题出在 object temp = oBFormatter.Deserialize(dbStream); 上。一旦我尝试反序列化,我的 object 就是一个透明代理,我无法转换为 MyCustomObject!!如何取回我的原始对象?我怎么能在#@& 的名字中有一个 MemoryStream 对象....在内存中...准备序列化...突然又变成了透明代理。

我很迷茫。感谢帮助。我会为得到答案的人祈祷#@& ;)

编辑 1好的,我必须说现在事情开始变得有意义了(尽管问题仍然存在)。我的问题:我的一侧有一个对象(包括状态),我需要将它存储在数据库中,以便几天后另一侧的另一个进程可以使用它。

我的对象不可序列化,因为它包装了一个未标记为可序列化的第三方对象。所以我唯一的选择似乎是编码,它返回一个 ObjRef,它又是可序列化的。但当然 - 几天后 - 我正在反序列化的对象只是引用,我的原始对象已经消失了。

我该如何解决我的问题?肯定有更多人遇到过这个问题,但我似乎找不到答案...

编辑 2好的,我想我要编写自己的可序列化类同构到第 3 方对象。然后运行整个第 3 方对象并存储/包装其状态信息等。然后将我的对象序列化到数据库......似乎是我唯一的选择。

编辑 3一段时间后再次开始解决这个问题。刚刚意识到 Edit 2 中发布的解决方案不起作用。我必须反序列化为第 3 方程序集知道的对象,因为它将继续对其执行操作。

最佳答案

您正在序列化 ObjRef这不是原始对象而是“远程引用”,包含传输引用的所有信息。

来自 MSDN(强调我的):

The ObjRef contains information that describes the Type and class of the object being marshaled, its exact location, and communication-related information on how to reach the remoting subdivision where the object is located.

After a class implementing MarshalByRefObject is marshaled, the ObjRef that represents it is transferred through a channel into another application domain, possibly in another process or computer. When the ObjRef is deserialized in the target application domain, it is parsed to create a transparent proxy for the remote MBR object. This operation is known as unmarshaling.

编辑(因为提供了新信息):

有几种方法可以解决您的问题。它们都有自己的一套限制,我将在这里汇总:

  • 使用 XML 序列化 XmlSerializer . XML 序列化的不同之处在于它序列化和反序列化一个对象的所有公共(public)属性,而不是序列化字段和/或自定义数据(当 ISerializable 由要序列化的对象实现时)。因此,如果第 3 方对象只是数据容器,序列化公共(public)属性就足够了,并且它们提供了默认构造函数,那么您应该可以接受此解决方案。

  • 构建您自己的“低级”序列化代码,使用反射获取字段并序列化它们。这种方法通常需要您的应用程序在完全信任的情况下运行(通过反射反射(reflect)和修改私有(private)字段需要通常不存在于较低信任度中的权限)。以下是一些可能对您有所帮助的方法:FormatterServices.GetSerializableMembers()获取要序列化的字段,FormatterServices.GetObjectData()从对象实例中获取字段数据,FormatterServices.GetSafeUninitializedObject()当反序列化以创建一个新的、未初始化的实例(不调用构造函数)时,以及 FormatterServices.PopulateObjectMembers()将字段写回新实例。如果字段中只有可序列化的简单数据类型,则可以序列化和反序列化用于存储字段数据的 object[]

  • 您目前的想法是手动编写第 3 方对象的副本。这可能非常痛苦,并且基本上只有在 XML 序列化也可以工作的情况下才有效。如果属性对于 sinatce 是只读的,那么您将无法采用这种方法。

关于c# - 反序列化 MemoryStream - 意外行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3100464/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com