的 编组 强> 是告诉编译器如何在另一个环境/系统上表示数据的规则; 例如;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] public string cFileName; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)] public string cAlternateFileName;
因为您可以看到两个不同的字符串值表示为不同的值类型。
的 序列化 强> 将只转换对象内容,而不是表示(将保持相同)并遵守序列化规则,(导出或不导出)。例如,私有值不会被序列化,公共值为yes,对象结构将保持不变。
的 封送处理是指将函数的签名和参数转换为单字节数组。 强> 专门用于RPC的目的。
的 序列化更常用于将整个对象/对象树转换为字节数组 强> Marshaling将序列化对象参数,以便将它们添加到消息中并通过网络传递。 *序列化也可用于存储到磁盘。*
以下是两个更具体的例子:
序列化示例:
#include <stdio.h> #include <stdlib.h> #include <stdint.h> typedef struct { char value[11]; } SerializedInt32; SerializedInt32 SerializeInt32(int32_t x) { SerializedInt32 result; itoa(x, result.value, 10); return result; } int32_t DeserializeInt32(SerializedInt32 x) { int32_t result; result = atoi(x.value); return result; } int main(int argc, char **argv) { int x; SerializedInt32 data; int32_t result; x = -268435455; data = SerializeInt32(x); result = DeserializeInt32(data); printf("x = %s.\n", data.value); return result; }
在序列化中,数据以可以在以后存储和不平坦的方式展平。
编组演示:
(MarshalDemoLib.cpp)
#include <iostream> #include <string> extern "C" __declspec(dllexport) void *StdCoutStdString(void *s) { std::string *str = (std::string *)s; std::cout << *str; } extern "C" __declspec(dllexport) void *MarshalCStringToStdString(char *s) { std::string *str(new std::string(s)); std::cout << "string was successfully constructed.\n"; return str; } extern "C" __declspec(dllexport) void DestroyStdString(void *s) { std::string *str((std::string *)s); delete str; std::cout << "string was successfully destroyed.\n"; }
(MarshalDemo.c)
#include <Windows.h> #include <stdio.h> #include <stdlib.h> #include <stdint.h> int main(int argc, char **argv) { void *myStdString; LoadLibrary("MarshalDemoLib"); myStdString = ((void *(*)(char *))GetProcAddress ( GetModuleHandleA("MarshalDemoLib"), "MarshalCStringToStdString" ))("Hello, World!\n"); ((void (*)(void *))GetProcAddress ( GetModuleHandleA("MarshalDemoLib"), "StdCoutStdString" ))(myStdString); ((void (*)(void *))GetProcAddress ( GetModuleHandleA("MarshalDemoLib"), "DestroyStdString" ))(myStdString); }
在编组中,数据不一定需要展平,但需要将其转换为另一种替代表示。所有的铸造都是编组,但并非所有的编组都是铸造。
Marshaling不需要涉及动态分配,它也可以只是结构之间的转换。例如,您可能有一对,但该函数期望该对的第一个和第二个元素是相反的;你将一对转换成memcpy对另一对将无法完成这项工作,因为fst和snd会被翻转。
#include <stdio.h> typedef struct { int fst; int snd; } pair1; typedef struct { int snd; int fst; } pair2; void pair2_dump(pair2 p) { printf("%d %d\n", p.fst, p.snd); } pair2 marshal_pair1_to_pair2(pair1 p) { pair2 result; result.fst = p.fst; result.snd = p.snd; return result; } pair1 given = {3, 7}; int main(int argc, char **argv) { pair2_dump(marshal_pair1_to_pair2(given)); return 0; }
当你开始处理许多类型的标记联合时,编组的概念变得尤为重要。例如,您可能会发现很难让JavaScript引擎为您打印“c字符串”,但您可以要求它为您打印一个包装的c字符串。或者,如果要在Lua或Python运行时中从JavaScript运行时打印字符串。它们都是字符串,但如果没有编组,往往不会相处。
我最近遇到的烦恼是,JScript数组将C#编组为“__ComObject”,并且没有记录的方式来使用此对象。我可以找到它所在的地址,但我真的不知道其他任何事情,所以真正弄清楚它的唯一方法是以任何可能的方式戳它并希望找到有关它的有用信息。因此,使用更友好的界面(如Scripting.Dictionary)创建新对象变得更加容易,将JScript数组对象中的数据复制到其中,并将该对象传递给C#而不是JScript的默认数组。
test.js:
var x = new ActiveXObject("Dmitry.YetAnotherTestObject.YetAnotherTestObject"); x.send([1, 2, 3, 4]);
YetAnotherTestObject.cs
using System; using System.Runtime.InteropServices; namespace Dmitry.YetAnotherTestObject { [Guid("C612BD9B-74E0-4176-AAB8-C53EB24C2B29"), ComVisible(true)] public class YetAnotherTestObject { public void send(object x) { System.Console.WriteLine(x.GetType().Name); } } }
上面打印“__ComObject”,从C#的角度来看,它有点像黑盒子。
另一个有趣的概念是你可能已经理解了如何编写代码,以及知道如何执行指令的计算机,因此作为程序员,你有效地整理了你希望计算机从你的大脑到程序做什么的概念。图片。如果我们有足够好的marshallers,我们可以想到我们想要做什么/改变什么,并且程序会改变这种方式而无需在键盘上打字。所以,如果你有办法在你真正想要编写分号的几秒钟内存储大脑中的所有物理变化,你可以将这些数据编组成一个信号来打印分号,但这是极端的。
两者都有一个共同点 - 就是这样 序列化 一个东西。序列化用于传输对象或存储它们。但:
的 因此序列化是编组的一部分。 强>
基本代码 是告诉Object的接收者可以找到该对象的实现的信息。任何认为它可能将对象传递给之前可能没有看到它的另一个程序的程序必须设置代码库,以便接收方可以知道从哪里下载代码,如果它没有本地可用的代码。在对对象进行反序列化时,接收器将从中获取代码库并从该位置加载代码。
来自 编组(计算机科学) 维基百科文章:
术语“marshal”被认为与Python标准库中的“serialize”同义 1 ,但这些术语在Java相关的RFC 2713中不是同义词: “编组”对象意味着以这样的方式记录其状态和代码库:当编组对象被“解组”时,可以通过自动加载对象的类定义来获得原始对象的副本。您可以封送任何可序列化或远程的对象。编组就像序列化一样,除了编组还记录代码库。编组与序列化的不同之处在于编组处理特殊的远程对象。 (RFC 2713) “序列化”对象意味着将其状态转换为字节流,使得字节流可以转换回对象的副本。
术语“marshal”被认为与Python标准库中的“serialize”同义 1 ,但这些术语在Java相关的RFC 2713中不是同义词:
“编组”对象意味着以这样的方式记录其状态和代码库:当编组对象被“解组”时,可以通过自动加载对象的类定义来获得原始对象的副本。您可以封送任何可序列化或远程的对象。编组就像序列化一样,除了编组还记录代码库。编组与序列化的不同之处在于编组处理特殊的远程对象。 (RFC 2713)
“序列化”对象意味着将其状态转换为字节流,使得字节流可以转换回对象的副本。
因此,编组也可以节省 码 字节流中的对象除了状态之外。
编组和序列化是 松弛地 在远程过程调用的上下文中是同义的,但在语义上是不同的意图。
特别是,编组是关于从这里到那里获取参数,而序列化是关于将结构化数据复制到诸如字节流之类的基本形式或从基本形式复制结构化数据。从这个意义上讲,序列化是执行编组的一种方法,通常实现按值传递语义。
对象也可以通过引用进行编组,在这种情况下,“在线上”的数据只是原始对象的位置信息。但是,这样的对象可能仍然适合于序列化。
正如@Bill所提到的,可能还有其他元数据,例如代码库位置甚至是对象实现代码。
Marshaling实际上使用了序列化过程,但主要区别在于它仅在序列化中仅数据成员和对象本身被序列化而不是签名,但在编组对象+代码库(其实现)中也将转换为字节。
编组是使用JAXB将java对象转换为xml对象的过程,以便可以在Web服务中使用它。
我认为主要区别在于编组据说还涉及代码库。换句话说,您将无法将对象编组和解组为另一个类的状态等效实例。 。
序列化只是意味着您可以存储对象并重新获得等效状态,即使它是另一个类的实例。
话虽如此,它们通常是同义词。
编组通常在相对密切相关的过程之间进行;序列化不一定有这种期望。因此,例如,当您在进程之间编组数据时,您可能希望仅将REFERENCE发送到可能昂贵的数据进行恢复,而对于序列化,您可能希望将其全部保存,以便在反序列化时正确地重新创建对象。
将它们视为同义词,它们都有一个生产者将东西发送给消费者......最后,实例的字段被写入字节流,而另一端则反向出现,并且具有相同的实例。
注意 - java RMI还包含对传输收件人丢失的类的支持...