【问题标题】:Migrate serialized objects to new version将序列化对象迁移到新版本
【发布时间】:2010-02-04 17:59:00
【问题描述】:

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

我以前的对象。

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

【问题讨论】:

    标签: c# remoting


    【解决方案1】:

    我最近实际上做了类似的事情,我创建了一个简单的控制台应用程序,能够将一些序列化对象从一个版本转换为另一个版本。我只是使用两个版本的 dll 和反射来读取和写入不同属性的值。也许您会发现这对您很有帮助;)

    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;
        }
    

    【讨论】:

    • 谢谢托马斯,但我正在考虑 ISurrogateSerialization,但它是一个开始。如果我能获得更多想法和代码示例,我仍然会很感激我如何解决这个问题。
    • 您好 Netmatrix,您是否找到了其他解决方案。你愿意分享吗?
    【解决方案2】:

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

    2) 该实用程序以非序列化方式将您的对象写入数据库(即,每个字段中都有一个数据,等等...)。

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

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

    随后出现了数据库格式、INI 文件等,专门用于满足这一需求,因此将数据保存为一种格式,然后能够无错误地读取它。

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

    在最坏的情况下,将您的数据存储为 XML,而不是序列化的二进制流。此外,我无法保证我从 MS 那里了解到来自一个 .NET 版本的序列化数据将能够从另一个版本中读取。尽可能将您的数据转换为清晰易读的格式。

    【讨论】:

      猜你喜欢
      • 2013-11-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-03-06
      相关资源
      最近更新 更多