组织文件版本迁移代码的最佳方式是什么?

发布于 2024-08-15 10:37:44 字数 1210 浏览 4 评论 0原文

我正在通过 API 为另一个程序编写插件。为了保存其当前状态,我的插件将 Project 对象的实例序列化为 XML 并将其存储在用户字符串中,将其存储到文件中,这是 API 提供的功能。它还存储一个单独的字符串,其中包含当前正在使用的插件的版本号。

当用户打开文件时,我的插件会检查版本号。如果当前插件版本与文件中存储的版本不同,则会弹出一条消息,警告用户版本不同,并且该文件可能会导致插件崩溃。

我更愿意提供一组迁移脚本,当用户在较新版本的插件中打开旧文件时,这些脚本会自动运行。但我的问题是这些通常去哪里以及它们是如何组织的?

另外,我的 Project 类在版本之间发生了显着变化,其中尝试从旧文件反序列化项目将因新 Project 类而失败。我不想在程序集中保留 Project 类的每个版本的副本,但同时必须解析 XML 会更加痛苦。假设解析 XML 是最好的选择,有人可以建议一种比下面的代码更有组织的方法吗?

public string MigrateProject(int fileVersion, int plugInversion, string proj)
{
    if(fileVersion>plugInversion)
    {
       //tell user to upgrade their copy of the plugin
       return null;
    }

    if(fileVersion ==1)
    { 
        string v2 = Migrate1to2(serializedProject);
        string v3 = Migrate2to3(v2);
        string v4 = Migrate3to4(v3);
        return v4;
    }
    else if(fileVersion ==2)
    { 
        string v3 = Migrate2to3(serializedProject);
        string v4 = Migrate3to4(v3);
        return v4;
    }
    else if(fileVersion ==3)
    { 
        string v4 = Migrate3to4(serializedProject);
        return v4;
    }
    else 
    {
         //could not migrate project message
         return null;
    }
}

I'm writing a plug-in for another program through an API. To save it's current state, my plugin stores an instance of a Project object to the file by serializing it to XML and storing it in a user string, a feature provided by the API. It also stores a separate string that contains the version number of the plug-in currently being used.

When a user opens a file my plug-in checks the version numbers. If the current plug-in version is not the same as the version stored in the file it pops up a message warning the user about the different version and that the file might cause the plug-in to crash.

I'd much rather provide a set of migration scripts that run automatically when a user opens an older file in a newer version of the plug-in. My question though is where do these usually go and how are they organized?

Also say my Project class changes significantly between versions where trying to deserialize the project from an old file will fail with the new Project class. I don't want to keep copies of every version of the Project class is my assembly, but at the same time having to parse through the XML would be even more painful. Assuming parsing the XML is the best option can anyone suggest a more organized way of doing this then the code below?

public string MigrateProject(int fileVersion, int plugInversion, string proj)
{
    if(fileVersion>plugInversion)
    {
       //tell user to upgrade their copy of the plugin
       return null;
    }

    if(fileVersion ==1)
    { 
        string v2 = Migrate1to2(serializedProject);
        string v3 = Migrate2to3(v2);
        string v4 = Migrate3to4(v3);
        return v4;
    }
    else if(fileVersion ==2)
    { 
        string v3 = Migrate2to3(serializedProject);
        string v4 = Migrate3to4(v3);
        return v4;
    }
    else if(fileVersion ==3)
    { 
        string v4 = Migrate3to4(serializedProject);
        return v4;
    }
    else 
    {
         //could not migrate project message
         return null;
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

油饼 2024-08-22 10:37:44

XmlSerializer 不具有版本容忍性,您无需包含可以在手动执行反序列化时执行操作的版本字段。

BinaryFormatter 支持的版本与 SoapFormatter 和 DataContractSerializer

您仍然需要处理转换,并且可以通过这种方式轻松地剪切代码:

if(fileVersion ==1)
{ 
    serializedProject = Migrate1to2(serializedProject);
    fileVersion = 2;
}
if(fileVersion ==2)
{ 
    serializedProject = Migrate2to3(serializedProject);
    fileVersion = 3;
}
if(fileVersion ==3)
{ 
    serializedProject = Migrate3to4(serializedProject);
    fileVersion = 4
}
else 
{
     //could not migrate project message
     return null;
}

XmlSerializer is not version tolerant, without you including a version field which you can act on in doing deserialization manually.

BinaryFormatter supports versions as does SoapFormatter and DataContractSerializer.

You would still need to handle the conversion, and could easily cut code this way:

if(fileVersion ==1)
{ 
    serializedProject = Migrate1to2(serializedProject);
    fileVersion = 2;
}
if(fileVersion ==2)
{ 
    serializedProject = Migrate2to3(serializedProject);
    fileVersion = 3;
}
if(fileVersion ==3)
{ 
    serializedProject = Migrate3to4(serializedProject);
    fileVersion = 4
}
else 
{
     //could not migrate project message
     return null;
}
你怎么敢 2024-08-22 10:37:44

将迁移方法存储在如下列表中:

List<Func<string,string>> myMigrateMethods = new List<Func<string,string>>();
myMigrateMethods.Add(Migrate1To2);
myMigrateMethods.Add(Migrate2To3);
myMigrateMethods.Add(Migrate3To4);

然后从适当的方法开始迭代列表:

public string MigrateProject(int fileVersion, int plugInversion, string proj)
{
    if(fileVersion>plugInversion)
    {
       //tell user to upgrade their copy of the plugin
       return null;
    }

    //user already at max version
    if(fileVersion >= (myMigrateMethods.Length-1)) return null;

    var firstMigrateMethodNeeded = (fileVersion-1); //array is 0-based

    var output = serializedProject;
    for(var i= firstMigrateMethodNeeded; i< myMigrateMethods.Length; i++)
    {
       output = myMigrateMethods[i](output);
    }

    return output;

}

Store your migrate methods in a list like this:

List<Func<string,string>> myMigrateMethods = new List<Func<string,string>>();
myMigrateMethods.Add(Migrate1To2);
myMigrateMethods.Add(Migrate2To3);
myMigrateMethods.Add(Migrate3To4);

Then iterate through the list starting at the appropriate method:

public string MigrateProject(int fileVersion, int plugInversion, string proj)
{
    if(fileVersion>plugInversion)
    {
       //tell user to upgrade their copy of the plugin
       return null;
    }

    //user already at max version
    if(fileVersion >= (myMigrateMethods.Length-1)) return null;

    var firstMigrateMethodNeeded = (fileVersion-1); //array is 0-based

    var output = serializedProject;
    for(var i= firstMigrateMethodNeeded; i< myMigrateMethods.Length; i++)
    {
       output = myMigrateMethods[i](output);
    }

    return output;

}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文