上位互換
ファイルを読み書きできるソフトを更新して、ファイルフォーマットが変わったときにも容易に上位互換を保つ方法。
ファイル形式をXMLにしておけば、要素が増えても減っても対応できるが、構造が変わるとダメだ。
以下のようにすれば、古い型 DataDoc1のファイルでも新しい型 DataDocのファイルでもそのまま読める。
[Version(1)] [XmlRoot("DataDoc")] public class DataDoc1 { public int Num; public DataDoc Create() { DataDoc dd = new DataDoc(); dd.NumList.Add(Num); return dd; } } [Version(2)] public class DataDoc { public int Version { get { VersionAttribute[] va = (VersionAttribute[])GetType(). GetCustomAttributes(typeof(VersionAttribute), false); return va[0].Version; } set { } } [XmlArrayItem("Num")] public List<int> NumList; public DataDoc() { NumList = new List<int>(); } public static DataDoc Load(string fnam) { DataDoc dd = null; string s; int version = -1; using (StreamReader sr = new StreamReader(fnam)) { while ((s = sr.ReadLine().Trim()) != null) if (s.StartsWith("<Version>")) break; if (string.IsNullOrEmpty(s)) return dd; version = int.Parse(s.Substring(9, s.IndexOf('<', 1) - 9)); } using (StreamReader sr = new StreamReader(fnam)) { XmlSerializer xs = new XmlSerializer(VesionedType(version)); object o = xs.Deserialize(sr); MethodInfo mi = o.GetType().GetMethod("Create"); dd = (DataDoc)mi.Invoke(o, new object[] { }); } return dd; } public static Type VesionedType(int version) { Assembly asm = Assembly.GetExecutingAssembly(); foreach (Type typ in asm.GetTypes()) { VersionAttribute[] va = (VersionAttribute[])typ. GetCustomAttributes(typeof(VersionAttribute), false); if (va.Length > 0 && va[0].Version == version) return typ; } return null; } } /// <summary>バージョン付与</summary> [AttributeUsage(AttributeTargets.Class)] public class VersionAttribute : Attribute { /// <summary>バージョン</summary> public int Version; /// <summary>コンストラクタ</summary> public VersionAttribute(int v) { Version = v; } }
- バージョンはint型で管理しているが、stringでもよい。
- クラスごとにVersionAttributeでバージョンを付ける。
- 古い型から新しい型に変換するCreateメソッドを用意する。