将序列化对象迁移到新版本

时间:2010-02-04 17:59:00

标签: c# remoting

我想将数据库中先前序列化的对象迁移到新架构。

我以前的目标。

Public interface MyReport
{

    string Id { get; set;}

    string Name { get; set;}

    Dictionary<string, string> PropColl { get; set;}
}

但由于某些原因,我们不得不进行界面更改

Public interface IMarkme
{
}

Public interface MyReport<T> where T : Imarkme
{

    string Id { get; set;}

    string Name { get; set;}

    T ExtendedProp { get; set;}
}

Public NewProp : Imarkme
{
    /// some code here 
}

因此,您可以看到我的界面已被修改,我想将基于MyReport序列化的序列化对象迁移到MyReport 有人可以提供一些输入作为我应该编写的实用程序,这可以帮助我实现将序列化对象迁移到新修改的接口版本。

谢谢, AG

2 个答案:

答案 0 :(得分:1)

我最近做过类似的事情,在那里我创建了一个简单的控制台应用程序,以便能够将一些序列化对象从一个版本转换为另一个版本。我只是使用dll和reflection的两个版本来读取和写入不同属性的值。可能你会发现这有助于作为灵感;)

static void Main(string[] args)
    {
        object test;

        AppDomain.CurrentDomain.AssemblyResolve += domain_AssemblyResolve;


        using (var con = new SqlConnection(connectionString))
        {
            using (var cmd = new SqlCommand())
            {
                cmd.CommandText = "select top 1 Data_Blob from dbo.Serialized";
                cmd.CommandType = CommandType.Text;
                cmd.Connection = con;

                con.Open();
                var blob = (byte[])cmd.ExecuteScalar();

                var bf = new BinaryFormatter();
                var stream = new MemoryStream(blob);
                bf.AssemblyFormat = FormatterAssemblyStyle.Full;
                test = bf.Deserialize(stream);
            }
        }

        var objNewVersion = Activator.CreateInstance(Type.GetType("ObjectGraphLibrary.Test, ObjectGraphLibrary, Version=1.0.0.10, Culture=neutral, PublicKeyToken=33c7c38cf0d65826"));


        var oldType = test.GetType();
        var newType = objNewVersion.GetType();

        var oldName = (string) oldType.GetProperty("Name").GetValue(test, null);
        var oldAge = (int) oldType.GetProperty("Age").GetValue(test, null);

        newType.GetProperty("Name").SetValue(objNewVersion, oldName, null);
        newType.GetProperty("DateOfBirth").SetValue(objNewVersion, DateTime.Now.AddYears(-oldAge), null);


        Console.Read();
    }

    static Assembly domain_AssemblyResolve(object sender, ResolveEventArgs args)
    {
        var assName = new AssemblyName(args.Name);

        var uriBuilder = new UriBuilder(Assembly.GetExecutingAssembly().CodeBase);
        var assemblyPath = Uri.UnescapeDataString(uriBuilder.Path);
        var codeBase = Path.GetDirectoryName(assemblyPath);

        var assPath = Path.Combine(codeBase, string.Format("old\\{0}.{1}.{2}.{3}\\{4}.dll", assName.Version.Major,
                                                 assName.Version.Minor, assName.Version.Build,
                                                 assName.Version.Revision, assName.Name));

        return File.Exists(assPath) ? Assembly.LoadFile(assPath) : null;
    }

答案 1 :(得分:0)

1)编写一个实用程序,读取旧对象定义中的序列化对象。

2)该实用程序以非序列化方式将对象写入数据库(即每个字段中包含一个数据等)。

不要养成序列化对象的习惯,并将其存储在持久存储中以便以后检索(很多)。序列化不是为此而构建的。

过去你遇到过C程序员的问题:他们会在内存中创建一个struct,将该struct保存到文件中。然后结构的成员会改变,他们会想知道如何读回它,因为数据的编码方式不同。

然后是数据库格式,INI文件等,专门用于满足这种需求,因此以一种格式保存数据,然后能够无误地读取数据。

所以不要重复过去的错误。创建序列化是为了促进短期二进制存储以及通过TCP / IP传输对象的能力。

最糟糕的是,将数据存储为XML,而不是序列化的二进制流。此外,我无法保证我从MS了解到可以从一个版本的.NET中读取序列化数据。尽可能将数据转换为易读的格式。