Answers:
在远程过程调用的上下文中,封送处理和序列化是松散的同义词,但是从意图上来说在语义上有所不同。
特别地,封送处理是关于从此处获取参数,而序列化是关于向诸如字节流之类的原始形式复制结构化数据。从这个意义上讲,序列化是执行封送处理的一种方法,通常实现按值传递语义。
还可以通过引用将对象编组,在这种情况下,“在线”数据仅仅是原始对象的位置信息。但是,这样的对象可能仍然适合于值序列化。
正如@Bill所提到的,可能存在其他元数据,例如代码库位置甚至对象实现代码。
I
,大写更改等。
两者都有一个共同点- 序列化对象。序列化用于传输对象或存储对象。但:
因此,序列化是编组的一部分。
CodeBase是一种信息,它告诉Object的接收者可以在哪里找到该对象的实现。任何认为它可能曾经将一个对象传递给另一个可能之前从未看过它的程序的程序,都必须设置代码库,以便接收方可以知道从哪里下载代码(如果它在本地没有可用的代码)。接收器将在反序列化对象时从其获取代码库,并从该位置加载代码。
invokeAndWait
和Forms Invoke
,它们封送对UI线程的同步调用,而无需进行序列化。
the implementation of this object
?你能不能给一个具体的例子Serialization
和Marshalling
?
从编组(计算机科学)维基百科文章中:
在Python标准库1中,术语“编组”被视为与“序列化”同义,但是在Java相关的RFC 2713中,术语不是同义的:
“封送”一个对象意味着以一种方式记录其状态和代码库,以便在“解组”被封送的对象时,可以通过自动加载该对象的类定义来获取原始对象的副本。您可以封送可序列化或远程的任何对象。封送就像序列化,只是封送还记录代码库。封送与序列化的不同之处在于,封送特别处理远程对象。(RFC 2713)
“序列化”对象意味着将其状态转换为字节流,以便可以将字节流转换回该对象的副本。
因此,编组除了将对象的状态保存外,还将其代码库保存在字节流中。
编组是告诉编译器如何在另一个环境/系统上表示数据的规则;例如;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
public string cFileName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)]
public string cAlternateFileName;
如您所见,两个不同的字符串值表示为不同的值类型。
序列化将仅转换对象内容,而不转换表示形式(保持不变),并遵守序列化规则(导出内容或不导出内容)。例如,私有值将不会序列化,公共值是,并且对象结构将保持不变。
这是两者的更具体的示例:
序列化示例:
#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);
}
在封送处理中,数据不必一定要展平,但需要将其转换为其他替代表示形式。所有铸件都是封送,但并非所有封送都是铸件。
封送处理不需要涉及动态分配,它也可以只是结构之间的转换。例如,您可能有一对,但函数希望该对的第一个和第二个元素处于相反的位置;例如,您将一对配对强制转换/存储将无法完成任务,因为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数组以“ __ComObject”的形式编组到C#,并且没有使用该对象的文档记录方式。我可以找到它的地址,但是我真的对它一无所知,所以真正弄清楚它的唯一方法就是以任何可能的方式戳一下它,并希望找到关于它的有用信息。因此,使用诸如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#的角度来看,它有点像一个黑匣子。
另一个有趣的概念是,您可能了解如何编写代码,以及一台知道如何执行指令的计算机,因此,作为程序员,您正在有效地编排您希望计算机从大脑到程序执行的概念。图片。如果我们有足够好的编组员,我们可以考虑一下我们想做/更改的事情,程序将以这种方式更改而无需在键盘上键入。因此,如果您有办法在真正想写分号的地方存储大脑中所有物理变化几秒钟,则可以将该数据编组为信号以打印分号,但这是一个极端。
我对编组的理解与其他答案不同。
序列化:
使用约定生成或重新水化对象图的线格式版本。
编组:
通过使用映射文件来生成或再水化对象图的线格式版本,以便可以自定义结果。该工具可以从遵守约定开始,但是重要的区别是自定义结果的能力。
合同优先开发:
编组在合同优先开发的背景下很重要。
Hydrating an object is taking an object that exists in memory, that doesn't yet contain any domain data ("real" data), and then populating it with domain data (such as from a database, from the network, or from a file system).
字节流 -流是数据序列。输入流-从源读取数据。输出流-将数据写入目标。Java字节流用于逐字节执行输入/输出(一次8位)。字节流适用于处理原始数据,例如二进制文件。Java字符流用于一次执行2个字节的输入/输出,因为字符是使用Java中的Unicode约定存储的,每个字符2个字节。当我们处理(读/写)文本文件时,字符流很有用。
RMI(远程方法调用) -一种API,提供了一种在Java中创建分布式应用程序的机制。RMI允许对象调用在另一个JVM中运行的对象上的方法。
都 序列化和编组松散地作为同义词使用。这里有一些区别。
序列化 -对象的数据成员被写入二进制形式或字节流(然后可以写入文件/内存/数据库等)。一旦将对象数据成员写入二进制形式,就无法保留有关数据类型的信息。
编组 -将对象序列化(转换为二进制格式的字节流),并附加数据类型+ Codebase,然后将其传递给Remote Object(RMI)。编组会将数据类型转换为预定的命名约定,以便可以相对于初始数据类型进行重构。
因此,序列化是编组的一部分。
代码库是一种信息,它告诉Object的接收者可以在哪里找到该对象的实现。任何认为它可能曾经将一个对象传递给另一个可能之前从未看过它的程序的程序,都必须设置代码库,以便接收方可以知道从哪里下载代码(如果它在本地没有可用的代码)。接收器将在反序列化对象后从其获取代码库,并从该位置加载代码。(复制自@Nasir答案)
序列化几乎就像对象使用的内存的愚蠢内存转储,而封送处理则存储有关自定义数据类型的信息。
从某种意义上说,序列化通过传递值的方式执行封送处理,因为没有传递数据类型的信息,只有原始形式传递给字节流。
如果流从一个操作系统转到另一个操作系统,并且不同的操作系统具有不同的表示相同数据的方式,则序列化可能会遇到与大端,小端相关的问题。另一方面,编组在OS之间进行迁移非常好,因为结果是更高级别的表示。
封送处理实际上使用序列化过程,但是主要区别在于,在序列化中,仅数据成员和对象本身得到序列化,而没有签名,而在封送对象+代码库(其实现)中也将转换为字节。
编组是使用JAXB将Java对象转换为xml对象,以便可以在Web服务中使用的过程。