Click here to Skip to main content
15,899,026 members
Home / Discussions / C#
   

C#

 
Questionhelp to deal with graph data structure Pin
Mahdi_mnj23-Sep-11 12:10
Mahdi_mnj23-Sep-11 12:10 
AnswerRe: help to deal with graph data structure Pin
SledgeHammer0123-Sep-11 13:53
SledgeHammer0123-Sep-11 13:53 
AnswerRe: help to deal with graph data structure Pin
BillWoodruff24-Sep-11 0:04
professionalBillWoodruff24-Sep-11 0:04 
AnswerRe: help to deal with graph data structure Pin
BobJanova26-Sep-11 1:33
BobJanova26-Sep-11 1:33 
GeneralRe: help to deal with graph data structure Pin
Mahdi_mnj26-Sep-11 4:32
Mahdi_mnj26-Sep-11 4:32 
GeneralRe: help to deal with graph data structure Pin
BobJanova26-Sep-11 5:54
BobJanova26-Sep-11 5:54 
GeneralRe: help to deal with graph data structure Pin
Mahdi_mnj26-Sep-11 4:50
Mahdi_mnj26-Sep-11 4:50 
QuestionVersioning the hard way Pin
lukeer23-Sep-11 4:43
lukeer23-Sep-11 4:43 
Hello experts,

even though I tried to create a minimal code sample, this question needs rather large code samples attached. Don't worry, all the interesting text is here, above all the code.

An application has to serialize data to a file and to de-serialize from that file. This works like a charm. The working example is attached in the first two code samples.

Now for the interesting part: the original working version is delivered to millions of satisfied customers. All their positive feedback encouraged the creation of version 2. Version 2 should of course be able to load data files from version 1. It is possible to change the data model without breaking compatibility, to some extend at least using ObsoleteAttribute and OptionalFieldAttribute. But when changes get more fundamental, other approaches are to be researched.

The third code sample shows an altered <cdoe>DataContainer class. In this example, it has to serialize one field that is not present in the original version. Therefore the well-known loading process fails.

To recover from the exception, another assembly is loaded. In my test case, it's the original assembly. It's delivered within the version 2 project resources.

The original assembly should load the legacy file. But it throws a TargetInvocationException instead. Its inner exception tells us that DataContainer has three members while there are only two de-serialized.

Now where does this legacy assembly know of DataContainer having three members nowadays?

It should have called its integrated version of DataContainer, which then had two members and therefore should load the legacy file without moaning.


However, here is the "minimal" working sample:
C#
// User Interface (unchanged throughout versions)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace Test_Serialization_Versioning_Heavy
{
    public partial class Form1 : Form
    {
        #region Declarations

        string _filename = string.Empty;
        DataContainer _dataContainer = new DataContainer();

        #endregion


        #region Init

        public Form1()
        {
            _filename = System.IO.Path.Combine(Application.StartupPath, "datafile.xml");
            InitializeComponent();
            ShowData();
        }

        #endregion


        #region User Interaction

        private void btLoad_Click(object sender, EventArgs e)
        {
            _dataContainer = DataContainer.LoadDataContainter(_filename);

            ShowData();
        }

        private void btSave_Click(object sender, EventArgs e)
        {
            _dataContainer.Save(_filename);
        }

        #endregion


        private void ShowData()
        {
            pgData.SelectedObject = _dataContainer;
        }


        #region Vom Windows Form-Designer generierter Code

        /// <summary>
        /// Erforderliche Designervariable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        /// Verwendete Ressourcen bereinigen.
        /// </summary>
        /// <param name="disposing">True, wenn verwaltete Ressourcen gelöscht werden sollen; andernfalls False.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        /// <summary>
        /// Erforderliche Methode für die Designerunterstützung.
        /// Der Inhalt der Methode darf nicht mit dem Code-Editor geändert werden.
        /// </summary>
        private void InitializeComponent()
        {
            this.tlpMain = new System.Windows.Forms.TableLayoutPanel();
            this.btLoad = new System.Windows.Forms.Button();
            this.btSave = new System.Windows.Forms.Button();
            this.pgData = new System.Windows.Forms.PropertyGrid();
            this.tlpMain.SuspendLayout();
            this.SuspendLayout();
            // 
            // tlpMain
            // 
            this.tlpMain.ColumnCount = 3;
            this.tlpMain.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 96F));
            this.tlpMain.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 96F));
            this.tlpMain.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
            this.tlpMain.Controls.Add(this.btLoad, 0, 0);
            this.tlpMain.Controls.Add(this.btSave, 1, 0);
            this.tlpMain.Controls.Add(this.pgData, 0, 1);
            this.tlpMain.Dock = System.Windows.Forms.DockStyle.Fill;
            this.tlpMain.Location = new System.Drawing.Point(0, 0);
            this.tlpMain.Name = "tlpMain";
            this.tlpMain.RowCount = 2;
            this.tlpMain.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 35F));
            this.tlpMain.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
            this.tlpMain.Size = new System.Drawing.Size(386, 392);
            this.tlpMain.TabIndex = 0;
            // 
            // btLoad
            // 
            this.btLoad.Anchor = System.Windows.Forms.AnchorStyles.None;
            this.btLoad.Location = new System.Drawing.Point(10, 6);
            this.btLoad.Name = "btLoad";
            this.btLoad.Size = new System.Drawing.Size(75, 23);
            this.btLoad.TabIndex = 0;
            this.btLoad.Text = "Load";
            this.btLoad.UseVisualStyleBackColor = true;
            this.btLoad.Click += new System.EventHandler(this.btLoad_Click);
            // 
            // btSave
            // 
            this.btSave.Anchor = System.Windows.Forms.AnchorStyles.None;
            this.btSave.Location = new System.Drawing.Point(106, 6);
            this.btSave.Name = "btSave";
            this.btSave.Size = new System.Drawing.Size(75, 23);
            this.btSave.TabIndex = 1;
            this.btSave.Text = "Save";
            this.btSave.UseVisualStyleBackColor = true;
            this.btSave.Click += new System.EventHandler(this.btSave_Click);
            // 
            // pgData
            // 
            this.tlpMain.SetColumnSpan(this.pgData, 3);
            this.pgData.Dock = System.Windows.Forms.DockStyle.Fill;
            this.pgData.Location = new System.Drawing.Point(3, 38);
            this.pgData.Name = "pgData";
            this.pgData.Size = new System.Drawing.Size(380, 351);
            this.pgData.TabIndex = 2;
            // 
            // Form1
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(386, 392);
            this.Controls.Add(this.tlpMain);
            this.Name = "Form1";
            this.Text = "Form1";
            this.tlpMain.ResumeLayout(false);
            this.ResumeLayout(false);

        }

        private System.Windows.Forms.TableLayoutPanel tlpMain;
        private System.Windows.Forms.Button btLoad;
        private System.Windows.Forms.Button btSave;
        private System.Windows.Forms.PropertyGrid pgData;

        #endregion
    }
}
The original DataContainer class
C#
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.Serialization;

namespace Test_Serialization_Versioning_Heavy
{
    [Serializable]
    public class DataContainer
    {
        #region Declarations

        private string _name = "NoName";
        private int _someNumber = 3;

        #endregion


        #region Information Disclosure

        public string Name
        {
            get { return (_name); }
            set { _name = value; }
        }

        public int SomeNumber
        {
            get { return (_someNumber); }
            set { _someNumber = value; }
        }

        #endregion


        #region Actions

        public void Save(string path)
        {
            using (
                System.IO.Stream writeStream = new System.IO.FileStream(
                    path,
                    System.IO.FileMode.OpenOrCreate
                )
            )
            {
                IFormatter formatter = new Formatters.Soap.SoapFormatter();

                formatter.Serialize(writeStream, this);
            }
        }


        public static DataContainer LoadDataContainter(string path)
        {
            using (System.IO.Stream readStream = new System.IO.FileStream(path, System.IO.FileMode.Open))
            {
                IFormatter formatter = new Formatters.Soap.SoapFormatter();

                return ((DataContainer)(formatter.Deserialize(readStream)));
            }
        }

        #endregion
    }
}
After updating
C#
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.Serialization;

namespace Test_Serialization_Versioning_Heavy
{
    [Serializable]
    public class DataContainer
    {
        #region Declarations

        private string _name = "NoName";
        private int _someNumber = 3;

        // This is new in version two.
        private double _newDouble = 5.2;

        #endregion


        #region Information Disclosure

        public string Name
        {
            get { return (_name); }
            set { _name = value; }
        }

        public int SomeNumber
        {
            get { return (_someNumber); }
            set { _someNumber = value; }
        }

        public double NewDouble
        {
            get { return (_newDouble); }
            set { _newDouble = value; }
        }

        #endregion


        #region Actions

        public void Save(string path)
        {
            using (
                System.IO.Stream writeStream = new System.IO.FileStream(
                    path,
                    System.IO.FileMode.OpenOrCreate
                )
            )
            {
                IFormatter formatter = new Formatters.Soap.SoapFormatter();

                formatter.Serialize(writeStream, this);
            }
        }


        public static DataContainer LoadDataContainter(string path)
        {
            try
            {
                using (
                    System.IO.Stream readStream = new System.IO.FileStream(
                        path,
                        System.IO.FileMode.Open
                    )
                )
                {
                    IFormatter formatter = new Formatters.Soap.SoapFormatter();

                    return ((DataContainer)(formatter.Deserialize(readStream)));
                }
            }
            catch (Exception ex)
            {
                // Try fallback method for loading legacy files
                System.Reflection.Assembly legacyAssembly = System.Reflection.Assembly.Load(Properties.Resources.LegacyAssemblyV1_0_0_0);
                Type[] legacyTypes = legacyAssembly.GetTypes();

                Type legacyProjectType = legacyAssembly.GetType("Test_Serialization_Versioning_Heavy.DataContainer");

                object legacyProjectObject = legacyProjectType.InvokeMember(
                    "LoadDataContainter",
                    System.Reflection.BindingFlags.Public
                        | System.Reflection.BindingFlags.Static
                        | System.Reflection.BindingFlags.InvokeMethod,
                    null, null,
                    new object[] { path }
                );

                // todo: return what really needs to be returned
                return (null);
            }
        }

        #endregion
    }
}


Ciao,


luker

AnswerRe: Versioning the hard way Pin
André Kraak23-Sep-11 23:03
André Kraak23-Sep-11 23:03 
GeneralRe: Versioning the hard way Pin
lukeer25-Sep-11 20:40
lukeer25-Sep-11 20:40 
AnswerRe: Versioning the hard way Pin
BobJanova26-Sep-11 2:02
BobJanova26-Sep-11 2:02 
QuestionC sharp GUI help needed! Pin
memed0922-Sep-11 20:42
memed0922-Sep-11 20:42 
AnswerRe: C sharp GUI help needed! Pin
memed0922-Sep-11 20:46
memed0922-Sep-11 20:46 
AnswerRe: C sharp GUI help needed! Pin
ScottM122-Sep-11 20:57
ScottM122-Sep-11 20:57 
GeneralRe: C sharp GUI help needed! Pin
memed0922-Sep-11 21:03
memed0922-Sep-11 21:03 
AnswerRe: C sharp GUI help needed! Pin
DaveAuld22-Sep-11 21:53
professionalDaveAuld22-Sep-11 21:53 
AnswerRe: C sharp GUI help needed! Pin
BillWoodruff23-Sep-11 0:43
professionalBillWoodruff23-Sep-11 0:43 
AnswerRe: C sharp GUI help needed! Pin
Bernhard Hiller26-Sep-11 1:07
Bernhard Hiller26-Sep-11 1:07 
QuestionHow can we restrict a user from changing the download path url's fine name. Pin
Member 825992122-Sep-11 11:21
Member 825992122-Sep-11 11:21 
AnswerRe: How can we restrict a user from changing the download path url's fine name. Pin
André Kraak22-Sep-11 11:47
André Kraak22-Sep-11 11:47 
AnswerRe: How can we restrict a user from changing the download path url's fine name. Pin
ScottM122-Sep-11 21:08
ScottM122-Sep-11 21:08 
AnswerRe: How can we restrict a user from changing the download path url's fine name. Pin
Pete O'Hanlon22-Sep-11 22:26
mvePete O'Hanlon22-Sep-11 22:26 
AnswerRe: How can we restrict a user from changing the download path url's fine name. Pin
Matt Meyer23-Sep-11 3:06
Matt Meyer23-Sep-11 3:06 
QuestionXML node is not a child of this node.... Pin
mwpeck22-Sep-11 10:46
mwpeck22-Sep-11 10:46 
AnswerRe: XML node is not a child of this node.... Pin
André Kraak22-Sep-11 11:05
André Kraak22-Sep-11 11:05 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.