定制系列化

2023-12-02

我有一些必须序列化的对象:

class Displayable{
  string name;
  Sprite icon;
}

The icon字段需要自定义序列化,因为Sprites 已经被序列化(在不同的文件中,具有自己的格式,由游戏引擎),我只需要存储一种引用它们的方法(比方说string,是里面的钥匙Dictionary<string, Sprite>).

Using BinaryFormatter我尝试实施ISerializable and ISerializationSurrogate但这两种方法都会在反序列化时创建 Sprite 对象的新实例,因此它们不适合我的情况。我想要具有相同的功能ISerializationSurrogate除非我不想要第一个参数SetObjectData(object obj, SerializationInfo info, StreamingContext context, ISurrogateSelector selector)因为我需要返回内存中已有的对象,而不是从反序列化器接收新实例并用数据填充它。

我还尝试了像 SharpSerializer 这样的外部库,但我不喜欢公共无参数构造函数的限制,而且它并不能真正让您自定义特殊类的序列化。 我读过有关 ProtoBuffers 的内容,但它不支持继承,我需要在其他地方使用它。

所以我的要求是:

  • 继承支持
  • 能够为某些类型定义自定义序列化
  • 这些自定义类型的反序列化不应自行创建实例

有图书馆这样做吗?

不然我是不是太挑剔了?通常如何实现对存储在其他地方的对象的引用的序列化?

先感谢您。

编辑: 这就是我想要的

public class SerializableSprite : ISerializationSurrogate
{
  public static Dictionary<string, Sprite> sprites;
  public void GetObjectData(object obj, SerializationInfo info, StreamingContext context) {
    Sprite sprite = obj as Sprite;
    info.AddValue("spriteKey", sprite.name);
  }
  // The first parameter in this function is a newly instantiated Sprite, which I don't need
  public object SetObjectData(object obj, SerializationInfo info, StreamingContext context, ISurrogateSelector selector) {
    return sprites[info.GetString("spriteKey")];
  }
}

为了阻止BinaryFormatter从创建一个新实例Sprite在反序列化期间,在序列化你可以打电话SerializationInfo.SetType(Type)指定要插入到序列化流中的备用类型信息(通常是某种代理类型)。反序列化期间SetObjectData()将传递代理实例而不是“真实”类型来初始化。该代理类型必须依次实现IObjectReference这样“真实”对象最终可以插入到对象图中,特别是通过在精灵表中查找它。

以下代码执行此操作:

class ObjectReferenceProxy<T> : IObjectReference
{
    public T RealObject { get; set; }

    #region IObjectReference Members

    object IObjectReference.GetRealObject(StreamingContext context)
    {
        return RealObject;
    }

    #endregion
}

public sealed class SpriteSurrogate : ObjectLookupSurrogate<string, Sprite>
{
    static Dictionary<string, Sprite> sprites = new Dictionary<string, Sprite>();
    static Dictionary<Sprite, string> spriteNames = new Dictionary<Sprite, string>();

    public static void AddSprite(string name, Sprite sprite)
    {
        if (name == null || sprite == null)
            throw new ArgumentNullException();
        sprites.Add(name, sprite);
        spriteNames.Add(sprite, name);
    }

    public static IEnumerable<Sprite> Sprites
    {
        get
        {
            return sprites.Values;
        }
    }

    protected override string GetId(Sprite realObject)
    {
        if (realObject == null)
            return null;
        return spriteNames[realObject];
    }

    protected override Sprite GetRealObject(string id)
    {
        if (id == null)
            return null;
        return sprites[id];
    }
}

public abstract class ObjectLookupSurrogate<TId, TRealObject> : ISerializationSurrogate where TRealObject : class
{
    public void Register(SurrogateSelector selector)
    {
        foreach (var type in Types)
            selector.AddSurrogate(type, new StreamingContext(StreamingContextStates.All), this);
    }

    IEnumerable<Type> Types
    {
        get
        {
            yield return typeof(TRealObject);
            yield return typeof(ObjectReferenceProxy<TRealObject>);
        }
    }

    protected abstract TId GetId(TRealObject realObject);

    protected abstract TRealObject GetRealObject(TId id);

    #region ISerializationSurrogate Members

    public void GetObjectData(object obj, SerializationInfo info, StreamingContext context)
    {
        var original = (TRealObject)obj;
        var id = GetId(original);
        info.AddValue("id", id);
        // use Info.SetType() to force the serializer to construct an object of type ObjectReferenceWrapper<TRealObject> during deserialization.
        info.SetType(typeof(ObjectReferenceProxy<TRealObject>));
    }

    public object SetObjectData(object obj, SerializationInfo info, StreamingContext context, ISurrogateSelector selector)
    {
        // Having constructed an object of type ObjectReferenceWrapper<TRealObject>, 
        // look up the real sprite using the id in the serialization stream.
        var wrapper = (ObjectReferenceProxy<TRealObject>)obj;
        var id = (TId)info.GetValue("id", typeof(TId));
        wrapper.RealObject = GetRealObject(id);
        return wrapper;
    }

    #endregion
}

然后将其应用到BinaryFormatter如下:

        var selector = new SurrogateSelector();
        var spriteSurrogate = new SpriteSurrogate();
        spriteSurrogate.Register(selector);

        BinaryFormatter binaryFormatter = new BinaryFormatter(selector, new StreamingContext());

Sample fiddle.

Update

虽然上面的代码可以在 .Net 3.5 及更高版本中运行,但它显然不能在unity3d尽管由于一些问题而编译成功IObjectReference。以下也适用于 .Net 3.5 及更高版本,并且还避免使用IObjectReference通过返回真实对象ISerializationSurrogate.SetObjectData()。因此它也应该在 unity3d 中工作(在评论中确认):

public sealed class SpriteSurrogate : ObjectLookupSurrogate<string, Sprite>
{
    static Dictionary<string, Sprite> sprites = new Dictionary<string, Sprite>();
    static Dictionary<Sprite, string> spriteNames = new Dictionary<Sprite, string>();

    public static void AddSprite(string name, Sprite sprite)
    {
        if (name == null || sprite == null)
            throw new ArgumentNullException();
        sprites.Add(name, sprite);
        spriteNames.Add(sprite, name);
    }

    public static IEnumerable<Sprite> Sprites
    {
        get
        {
            return sprites.Values;
        }
    }

    protected override string GetId(Sprite realObject)
    {
        if (realObject == null)
            return null;
        return spriteNames[realObject];
    }

    protected override Sprite GetRealObject(string id)
    {
        if (id == null)
            return null;
        return sprites[id];
    }
}

public abstract class ObjectLookupSurrogate<TId, TRealObject> : ISerializationSurrogate where TRealObject : class
{
    class SurrogatePlaceholder
    {
    }

    public void Register(SurrogateSelector selector)
    {
        foreach (var type in Types)
            selector.AddSurrogate(type, new StreamingContext(StreamingContextStates.All), this);
    }

    IEnumerable<Type> Types
    {
        get
        {
            yield return typeof(TRealObject);
            yield return typeof(SurrogatePlaceholder);
        }
    }

    protected abstract TId GetId(TRealObject realObject);

    protected abstract TRealObject GetRealObject(TId id);

    #region ISerializationSurrogate Members

    public void GetObjectData(object obj, SerializationInfo info, StreamingContext context)
    {
        var original = (TRealObject)obj;
        var id = GetId(original);
        info.AddValue("id", id);
        // use Info.SetType() to force the serializer to construct an object of type SurrogatePlaceholder during deserialization.
        info.SetType(typeof(SurrogatePlaceholder));
    }

    public object SetObjectData(object obj, SerializationInfo info, StreamingContext context, ISurrogateSelector selector)
    {
        // Having constructed an object of type SurrogatePlaceholder, 
        // look up the real sprite using the id in the serialization stream.
        var id = (TId)info.GetValue("id", typeof(TId));
        return GetRealObject(id);
    }

    #endregion
}

Sample 小提琴#2.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

定制系列化 的相关文章

  • 用 C++ 进行服装建模 [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我正在编写一些软件 最终会绘制一个人体框架 可以配置各种参数 并且计划是在假人身上放置某种衣服 我研究
  • 使用 Unity 在构造函数中使用属性依赖注入

    好的 我在基类中定义了一个依赖属性 我尝试在其派生类的构造函数内部使用它 但这不起作用 该属性显示为 null Unity 在使用 container Resolve 解析实例后解析依赖属性 我的另一种选择是将 IUnityContaine
  • VB.NET 相当于 C# 属性简写吗?

    是否有与 C 等效的 VB NET public string FirstName get set 我知道你能做到 Public Property name As String Get Return name ToString End Ge
  • 为 Visual Studio 2013 编译 Tesseract

    我正在尝试使用tesseract在 Visual Studio 2013 中 我在链接器 gt 输入 不是 libtesseract302 static lib 中使用 libtesseract302 lib 一切都正常 并且已编译并运行
  • 在新的浏览器进程中打开 URL

    我需要在新的浏览器进程中打开 URL 当浏览器进程退出时我需要收到通知 我当前使用的代码如下 Process browser new Process browser EnableRaisingEvents true browser Star
  • 在 Unity 进程和另一个 C# 进程之间进行本地 IPC 的最快方法 [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我希望每秒大约 30 次从 C 应用程序向我的 Unity 应用程序传送大量数据 由于 Unity 不支持映射内存和管道 我考虑了 t
  • 读取文件特定行号的有效方法。 (奖励:Python 手册印刷错误)

    我有一个 100 GB 的文本文件 它是来自数据库的 BCP 转储 当我尝试导入它时BULK INSERT 我在第 219506324 行上收到一个神秘错误 在解决此问题之前 我想看看这一行 但可惜的是我最喜欢的方法 import line
  • 用于检查项目文件中的项目变量和引用路径的 api

    我正在研究一个 net application VS2010 与 x 没有 解和变量号这些解决方案中的项目数量 我需要检查项目属性 特定于一定数量的项目 是否同质 并且检查 验证构建期间的参考路径 有没有一个API是这样的吗 如果没有 我该
  • 如何在 Linq 中获得左外连接?

    我的数据库中有两个表 如下所示 顾客 C ID city 1 Dhaka 2 New york 3 London 个人信息 P ID C ID Field value 1 1 First Name Nasir 2 1 Last Name U
  • 单击 form2 上的按钮触发 form 1 中的方法

    我对 Windows 窗体很陌生 我想知道是否可以通过单击表单 2 中的按钮来触发表单 1 中的方法 我的表格 1 有一个组合框 我的 Form 2 有一个 保存 按钮 我想要实现的是 当用户单击表单 2 中的 保存 时 我需要检查表单 1
  • 未经许可更改内存值

    我有一个二维数组 当我第一次打印数组的数据时 日期打印正确 但其他时候 array last i 的数据从 i 0 到 last 1 显然是一个逻辑错误 但我不明白原因 因为我复制并粘贴了 for 语句 那么 C 更改数据吗 I use g
  • PlaySound 可在 Visual Studio 中运行,但不能在独立 exe 中运行

    我正在尝试使用 Visual Studio 在 C 中播放 wav 文件 我将文件 my wav 放入项目目录中并使用代码 PlaySound TEXT my wav NULL SND FILENAME SND SYNC 我按下播放按钮 或
  • 如何将自定义 JSON 文件添加到 IConfiguration 中?

    我正在使用 asp net Autofac 我正在尝试加载自定义 JSON 配置文件 并基于该文件创建 实例化 IConfiguration 实例 或者至少将我的文件包含到默认情况下构建的 IConfiguration asp net 中
  • 如何使用 Mongodb C# 驱动程序连接多个集合

    我需要将 3 个集合与多个集合合并在一起 lookup我在 C 驱动程序中尝试过 它允许我 lookup用户采集但无法执行秒 lookup用于设置集合 有人可以帮忙吗 db Transactions aggregate lookup fro
  • 等待线程完成

    private void button1 Click object sender EventArgs e for int i 0 i lt 15 i Thread nova new Thread Method nova Start list
  • 如何从main方法调用业务对象类?

    我已将代码分为业务对象 访问层 如下所示 void Main Business object public class ExpenseBO public void MakeExpense ExpensePayload payload var
  • 如何在按钮单击时模拟按键 - Unity

    我对 Unity 中的脚本编写非常陌生 我正在尝试创建一个按钮 一旦单击它就需要模拟按下 F 键 要拾取一个项目 这是我当前的代码 在编写此代码之前我浏览了所有统一论坛 但找不到任何有效的东西 Code using System Colle
  • 英特尔 Pin 与 C++14

    问题 我有一些关于在 C 14 或其他 C 版本中使用英特尔 Pin 的问题 使用较新版本从较旧的 C 编译代码很少会出现任何问题 但由于 Intel Pin 是操作指令级别的 如果我使用 C 11 或 C 14 编译它 是否会出现任何不良
  • 使用 GhostScript.NET 打印 PDF DPI 打印问题

    我在用GhostScript NET http ghostscriptnet codeplex com打印 PDF 当我以 96DPI 打印时 PDF 打印效果很好 但有点模糊 如果我尝试以 600DPI 打印文档 打印的页面会被极大地放大
  • 如何使用 Word Automation 获取页面范围

    如何使用办公自动化找到 Microsoft Word 中第 n 页的范围 似乎没有 getPageRange n 函数 并且不清楚它们是如何划分的 这就是您从 VBA 执行此操作的方法 转换为 Matlab COM 调用应该相当简单 Pub

随机推荐

  • Django 管理员:如何将更多字段显示为链接?

    Django 的默认管理页面会自动将每个表的第一个标题设为编辑信息的链接 见下文 单击ID列数据将带您进入编辑所选表中字段的页面 在本例中Applicants 有没有办法改变这个设置 以便Surname是要编辑的链接 而不是ID 非常感谢
  • 使用 Ruby,获取给定 URL 的内容类型的最有效方法是什么?

    使用 Ruby 获取给定 URL 的内容类型的最有效方法是什么 如果我想要简单的代码 这就是我要做的 require open uri str open http example com str content type gt text h
  • 在空手道中设置全局配置值

    我正在尝试的是从功能文件中设置全局 karate config 值 我有一些与此非常相似的东西https github com intuit karate blob master karate demo src test java demo
  • 在组装战争中包含 Maven 依赖项?

    我正在创建一个程序集packaging war 我需要包含一些 jar 它们已在我的 war 中的 pom xml 中声明为项目依赖项 web inf lib 我怎样才能做到这一点 编辑于 15 10 我的项目创建了很少的程序集 其中之一应
  • Enter 键按下的行为类似于 JSF 中的提交

    如何使 Enter 键按下的行为类似于 JSF 中的提交 它与输入框一起使用 但不适用于输入秘密框 我以前没见过这个问题 此行为不太可能是特定于浏览器的 尝试在不同类型的浏览器中排除其中一种或另一种 IE6 7 8 FF Safari Ch
  • 在PythonunittestTestLoader中指定具体的测试用例

    我有以下文件夹结构 Unit smoke py Test1 Test1 py Test2 Test2 py 两个测试文件各有两个测试用例 File smoke py包含 suite1 unittest TestLoader discover
  • errno、strerror 和 Linux 系统调用

    我可以用strerror 获取文本表示errno使用 CRT 函数后的值 例如fopen 如果我使用open Linux系统调用代替CRT函数 它还设置errno失败时的价值 申请是否正确strerror 对此errno价值 如果没有 是否
  • 找不到有效的签名身份?

    我已经尝试用 mono 创建一个发行版本已经好几天了 我从我们的 团队代理 那里获得了发行配置文件和发行证书 并分别拖放到 xcode organizer 和 keychain access 上 但是仍然有警告消息显示 在您的钥匙串中找不到
  • Java解压字节数组

    在服务器 C 上 二进制数据使用以下方式压缩ZLib功能 compress2 并将其发送到客户端 Java 在客户端 Java 应使用以下代码片段解压缩数据 public static String unpack byte packedBu
  • SPARQL 中的幂(指数)和其他数学函数支持

    I am trying to write a SPARQL query where I want to filter on the square of something but I am simply unable to figure o
  • 如何使默认 bin 目录在 Eclipse 中可见? [复制]

    这个问题在这里已经有答案了 可能的重复 我该怎么做才能在 eclipse 上显示 bin 文件夹 我知道这是一个searing的重复项this问题 但是该问题中提供的答案对我不起作用或对我没有任何帮助 我正在尝试获取项目的默认输出文件夹 b
  • 更改资源字典中的 SolidColorBrush#Color 失败:属性为只读 [重复]

    这个问题在这里已经有答案了 我有一个SolidColorBrushApp xaml 中的资源如下所示
  • wireshark 如何在同一端口上使用两个 lua 解析器正确解析

    我正在编写lua脚本作为wireshark 1 12 4 插件来剖析我的私有协议 我有两个协议 我为每个协议编写一个lua脚本 两个lua脚本看起来如下 local my pro Proto MyPro My Protocol local
  • 程序从哪里分配内存?

    作为一名 C 和 C 程序员 我使用过malloc and new来分配内存 我只是想知道 操作系统如何分配内存 它是从 RAM 硬盘还是其他地方分配 我可以从硬盘借用内存以防万一吗 它实际上比你想象的要复杂得多 操作系统以 页面 的形式考
  • 如何在recycler视图中访问MainActivity的组件来制作onclick监听器?

    我创建了类似 YouTube 的应用程序 其中包含一个视频视图 顶部 和回收器视图 视频视图下方 我陷入困境 我想在 recyclerview 项目上创建 onclicklistner 并更改视频路径来更改视频 但是如何访问适配器类中的 v
  • PHP 中的 SFTP - 未定义的常量 CURLOPT_PROTOCOLS 和 CURLPROTO_SFTP?

    从我的 php 脚本中 我需要能够通过 sftp 将 csv 文件上传到远程服务器 我遵循了这个问题的公认答案 从 PHP 内部进行 SFTP 这是我的代码的样子
  • 使用公式将 Excel 子集列转换为数组

    我需要将帐号放入一个数组中 该数组在列选择上指示为 1 预期结果是 FD 002 17 FD 004 17 我计划在名称范围中使用它 子集感兴趣的表 我尝试使用 INDEX B2 B6 MATCH 1 A2 A6 1 但这失败了Match不
  • openFileInput() 和/或 openFileOutput() I/O 流默默失败

    我一直在研究 android 平台 研究不同的数据存储方式 现在我正在使用Context方法openFileInput and openFileOutput 正如这两种方法的文档告诉我的那样 我创建了一个名为 default 的文件 这是一
  • 几分钟后服务自动停止

    我正在创建一个服务 当活动处于后台以及整个应用程序被销毁时 该服务应该可以工作 我每隔 1 分钟调用一次服务中的位置坐标 但是 当我尝试这样做时 该服务会在 12 15 分钟后自动关闭 我希望该服务能够无休止地工作 直到并且除非它被用户交互
  • 定制系列化

    我有一些必须序列化的对象 class Displayable string name Sprite icon The icon字段需要自定义序列化 因为Sprites 已经被序列化 在不同的文件中 具有自己的格式 由游戏引擎 我只需要存储一