System.Version non sérialisé

J’ai une classe avec une propriété System.Version , qui ressemble à ceci:

  • Version
    • Construire: 111
    • Major: 1
    • MajorRévision: 0
    • Mineure: 1
    • Télévision mineure: 10
    • Révision: 10

Lorsque je sérialise la classe, la version est toujours vide:

  

La classe Client ressemble à:

 [Serializable] public class Client { public ssortingng Description; public ssortingng Directory; public DateTime ReleaseDate; public Version Version; } 

System.Version n’est pas sérialisable. Si vous examinez ses propriétés sur MSDN , vous verrez qu’elles n’ont pas de parameters … afin que le sérialiseur ne les stocke pas. Cependant, cette approche fonctionne toujours . Cet article (ancien mais fonctionne toujours) fournit une classe Version sérialisable. Pouvez-vous basculer vers cela et commencer?

Edité par tomfanning
J’ai repêché le code sur le site mort de archive.org, reproduit ci-dessous.

 using System; using System.Globalization; namespace CubicOrange.Version { ///  /// Serializable version of the System.Version class. ///  [Serializable] public class ModuleVersion : ICloneable, IComparable { private int major; private int minor; private int build; private int revision; ///  /// Gets the major. ///  ///  public int Major { get { return major; } set { major = value; } } ///  /// Gets the minor. ///  ///  public int Minor { get { return minor; } set { minor = value; } } ///  /// Gets the build. ///  ///  public int Build { get { return build; } set { build = value; } } ///  /// Gets the revision. ///  ///  public int Revision { get { return revision; } set { revision = value; } } ///  /// Creates a new  instance. ///  public ModuleVersion() { this.build = -1; this.revision = -1; this.major = 0; this.minor = 0; } ///  /// Creates a new  instance. ///  /// Version. public ModuleVersion(ssortingng version) { this.build = -1; this.revision = -1; if (version == null) { throw new ArgumentNullException("version"); } char[] chArray1 = new char[1] { '.' }; ssortingng[] textArray1 = version.Split(chArray1); int num1 = textArray1.Length; if ((num1 < 2) || (num1 > 4)) { throw new ArgumentException("Arg_VersionSsortingng"); } this.major = int.Parse(textArray1[0], CultureInfo.InvariantCulture); if (this.major < 0) { throw new ArgumentOutOfRangeException("version", "ArgumentOutOfRange_Version"); } this.minor = int.Parse(textArray1[1], CultureInfo.InvariantCulture); if (this.minor < 0) { throw new ArgumentOutOfRangeException("version", "ArgumentOutOfRange_Version"); } num1 -= 2; if (num1 > 0) { this.build = int.Parse(textArray1[2], CultureInfo.InvariantCulture); if (this.build < 0) { throw new ArgumentOutOfRangeException("build", "ArgumentOutOfRange_Version"); } num1--; if (num1 > 0) { this.revision = int.Parse(textArray1[3], CultureInfo.InvariantCulture); if (this.revision < 0) { throw new ArgumentOutOfRangeException("revision", "ArgumentOutOfRange_Version"); } } } } ///  /// Creates a new  instance. ///  /// Major. /// Minor. public ModuleVersion(int major, int minor) { this.build = -1; this.revision = -1; if (major < 0) { throw new ArgumentOutOfRangeException("major", "ArgumentOutOfRange_Version"); } if (minor < 0) { throw new ArgumentOutOfRangeException("minor", "ArgumentOutOfRange_Version"); } this.major = major; this.minor = minor; this.major = major; } ///  /// Creates a new  instance. ///  /// Major. /// Minor. /// Build. public ModuleVersion(int major, int minor, int build) { this.build = -1; this.revision = -1; if (major < 0) { throw new ArgumentOutOfRangeException("major", "ArgumentOutOfRange_Version"); } if (minor < 0) { throw new ArgumentOutOfRangeException("minor", "ArgumentOutOfRange_Version"); } if (build < 0) { throw new ArgumentOutOfRangeException("build", "ArgumentOutOfRange_Version"); } this.major = major; this.minor = minor; this.build = build; } ///  /// Creates a new  instance. ///  /// Major. /// Minor. /// Build. /// Revision. public ModuleVersion(int major, int minor, int build, int revision) { this.build = -1; this.revision = -1; if (major < 0) { throw new ArgumentOutOfRangeException("major", "ArgumentOutOfRange_Version"); } if (minor < 0) { throw new ArgumentOutOfRangeException("minor", "ArgumentOutOfRange_Version"); } if (build < 0) { throw new ArgumentOutOfRangeException("build", "ArgumentOutOfRange_Version"); } if (revision < 0) { throw new ArgumentOutOfRangeException("revision", "ArgumentOutOfRange_Version"); } this.major = major; this.minor = minor; this.build = build; this.revision = revision; } #region ICloneable Members ///  /// Clones this instance. ///  ///  public object Clone() { ModuleVersion version1 = new ModuleVersion(); version1.major = this.major; version1.minor = this.minor; version1.build = this.build; version1.revision = this.revision; return version1; } #endregion #region IComparable Members ///  /// Compares to. ///  /// Obj. ///  public int CompareTo(object version) { if (version == null) { return 1; } if (!(version is ModuleVersion)) { throw new ArgumentException("Arg_MustBeVersion"); } ModuleVersion version1 = (ModuleVersion)version; if (this.major != version1.Major) { if (this.major > version1.Major) { return 1; } return -1; } if (this.minor != version1.Minor) { if (this.minor > version1.Minor) { return 1; } return -1; } if (this.build != version1.Build) { if (this.build > version1.Build) { return 1; } return -1; } if (this.revision == version1.Revision) { return 0; } if (this.revision > version1.Revision) { return 1; } return -1; } #endregion ///  /// Equalss the specified obj. ///  /// Obj. ///  public override bool Equals(object obj) { if ((obj == null) || !(obj is ModuleVersion)) { return false; } ModuleVersion version1 = (ModuleVersion)obj; if (((this.major == version1.Major) && (this.minor == version1.Minor)) && (this.build == version1.Build) && (this.revision == version1.Revision)) { return true; } return false; } ///  /// Gets the hash code. ///  ///  public override int GetHashCode() { int num1 = 0; num1 |= ((this.major & 15) << 0x1c); num1 |= ((this.minor & 0xff) << 20); num1 |= ((this.build & 0xff) << 12); return (num1 | this.revision & 0xfff); } ///  /// Operator ==s the specified v1. ///  /// V1. /// V2. ///  public static bool operator ==(ModuleVersion v1, ModuleVersion v2) { return v1.Equals(v2); } ///  /// Operator >s the specified v1. ///  /// V1. /// V2. ///  public static bool operator >(ModuleVersion v1, ModuleVersion v2) { return (v2 < v1); } ///  /// Operator >=s the specified v1. ///  /// V1. /// V2. ///  public static bool operator >=(ModuleVersion v1, ModuleVersion v2) { return (v2 <= v1); } ///  /// Operator !=s the specified v1. ///  /// V1. /// V2. ///  public static bool operator !=(ModuleVersion v1, ModuleVersion v2) { return (v1 != v2); } ///  /// Operator <s the specified v1. ///  /// V1. /// V2. ///  public static bool operator <(ModuleVersion v1, ModuleVersion v2) { if (v1 == null) { throw new ArgumentNullException("v1"); } return (v1.CompareTo(v2) < 0); } ///  /// Operator <=s the specified v1. ///  /// V1. /// V2. ///  public static bool operator <=(ModuleVersion v1, ModuleVersion v2) { if (v1 == null) { throw new ArgumentNullException("v1"); } return (v1.CompareTo(v2) <= 0); } ///  /// Toes the ssortingng. ///  ///  public override ssortingng ToSsortingng() { if (this.build == -1) { return this.ToSsortingng(2); } if (this.revision == -1) { return this.ToSsortingng(3); } return this.ToSsortingng(4); } ///  /// Toes the ssortingng. ///  /// Field count. ///  public ssortingng ToSsortingng(int fieldCount) { object[] objArray1; switch (fieldCount) { case 0: { return ssortingng.Empty; } case 1: { return (this.major.ToSsortingng()); } case 2: { return (this.major.ToSsortingng() + "." + this.minor.ToSsortingng()); } } if (this.build == -1) { throw new ArgumentException(ssortingng.Format("ArgumentOutOfRange_Bounds_Lower_Upper {0},{1}", "0", "2"), "fieldCount"); } if (fieldCount == 3) { objArray1 = new object[5] { this.major, ".", this.minor, ".", this.build }; return ssortingng.Concat(objArray1); } if (this.revision == -1) { throw new ArgumentException(ssortingng.Format("ArgumentOutOfRange_Bounds_Lower_Upper {0},{1}", "0", "3"), "fieldCount"); } if (fieldCount == 4) { objArray1 = new object[7] { this.major, ".", this.minor, ".", this.build, ".", this.revision }; return ssortingng.Concat(objArray1); } throw new ArgumentException(ssortingng.Format("ArgumentOutOfRange_Bounds_Lower_Upper {0},{1}", "0", "4"), "fieldCount"); } } } 

Je préfère utiliser l’approche ci-dessous, je n’ai donc qu’une propriété de type VersionXml dans ma classe. Les opérateurs implicites sont vraiment utiles ici.

 [Serializable] [XmlType("Version")] public class VersionXml { public VersionXml() { this.Version = null; } public VersionXml(Version Version) { this.Version = Version; } [XmlIgnore] public Version Version { get; set; } [XmlText] [EditorBrowsable(EditorBrowsableState.Never), Browsable(false)] public ssortingng Value { get { return this.Version == null ? ssortingng.Empty : this.Version.ToSsortingng(); } set { Version temp; Version.TryParse(value, out temp); this.Version = temp; } } public static implicit operator Version(VersionXml VersionXml) { return VersionXml.Version; } public static implicit operator VersionXml(Version Version) { return new VersionXml(Version); } public override ssortingng ToSsortingng() { return this.Value; } } 

Vous pouvez utiliser la propriété proxy de chaîne:

 [XmlIgnore] public System.Version Version { get; set; } [EditorBrowsable(EditorBrowsableState.Never), Browsable(false)] public ssortingng version { get { if (this.Version == null) return ssortingng.Empty; else return this.Version.ToSsortingng(); } set { if(!Ssortingng.IsNullOrEmpty(value)) this.Version = new Version(value); } } 

Vous devez définir vos accesseurs get et set suit:

 public class Version { public int Build { get; set; } public int Major { get; set; } public int MajorRevision { get; set; } public int Minor { get; set; } public int MinorRevision { get; set; } public int Revision { get; set; } } // ... new XmlSerializer(typeof (Version)) .Serialize(Console.Out, new Version() { Build = 111, Major = 1, MajorRevision = 0, Minor = 1, MinorRevision = 10, Revision = 10 } ); 

J’ai eu cette sortie:

   111 1 0 1 10 10  

Plus précisément, System.Version n’est pas XML- sérialisable. Il est sérialisable avec un BinaryFormatter , par exemple:

 Version version = new Version(1, 2, 3, 4); using (MemoryStream stream = new MemoryStream()) { BinaryFormatter formatter = new BinaryFormatter(); formatter.Serialize(stream, version); stream.Position = 0; Version deserialized = (Version)formatter.Deserialize(stream); } 

J’ai nettoyé l’implémentation de Nick Craver pour qu’elle soit beaucoup plus concise et lisible, j’ai ajouté le support de la sérialisation XML (avec des atsortingbuts au lieu d’éléments séparés), mis en place une chaîne TypeConverter ainsi que corrigé quelques problèmes de comparaison pouvant donner lieu à NullReferenceExceptions ou des boucles infinies ( appeler les opérateurs surchargés de l’intérieur).

J’ai également utilisé des fonctionnalités C # 6.

 using System; using System.Collections.Generic; using System.ComponentModel; using System.Globalization; using System.Xml.Serialization; [Serializable] [TypeConverter(typeof(VersionCodeConverter))] public class VersionCode : ICloneable, IComparable, IEquatable { [XmlAtsortingbute] public int Major { get; private set; } [XmlAtsortingbute] public int Minor { get; private set; } [XmlAtsortingbute] public int Build { get; private set; } = -1; [XmlAtsortingbute] public int Revision { get; private set; } = -1; public VersionCode() { } public VersionCode(int major, int minor, int build = 0, int revision = 0) { if (major < 0) throw new ArgumentOutOfRangeException(nameof(major), $"{nameof(major)} cannot be less than 0"); if (minor < 0) throw new ArgumentOutOfRangeException(nameof(minor), $"{nameof(minor)} cannot be less than 0"); if (build < 0) throw new ArgumentOutOfRangeException(nameof(build), $"{nameof(build)} cannot be less than 0"); if (revision < 0) throw new ArgumentOutOfRangeException(nameof(revision), $"{nameof(revision)} cannot be less than 0"); Major = major; Minor = minor; Build = build; Revision = revision; } public VersionCode(string version) { if (version == null) throw new ArgumentNullException(nameof(version)); var components = new Stack(version.Split('.')); if (components.Count < 2 || components.Count > 4) throw new ArgumentException(nameof(version)); Major = int.Parse(components.Pop(), CultureInfo.InvariantCulture); if (Major < 0) throw new ArgumentOutOfRangeException(nameof(version), $"{nameof(Major)} cannot be less than 0"); Minor = int.Parse(components.Pop(), CultureInfo.InvariantCulture); if (Minor < 0) throw new ArgumentOutOfRangeException(nameof(version), $"{nameof(Minor)} cannot be less than 0"); if (!components.Any()) return; Build = int.Parse(components.Pop(), CultureInfo.InvariantCulture); if (Build < 0) throw new ArgumentOutOfRangeException(nameof(version), $"{nameof(Build)} cannot be less than 0"); if (!components.Any()) return; Revision = int.Parse(components.Pop(), CultureInfo.InvariantCulture); if (Revision < 0) throw new ArgumentOutOfRangeException(nameof(version), $"{nameof(Revision)} cannot be less than 0"); } public object Clone() => new VersionCode(Major, Minor, Build, Revision); public int CompareTo(VersionCode version) => Major != version.Major ? Major.CompareTo(version.Major) : Minor != version.Minor ? Minor.CompareTo(version.Minor) : Build != version.Build ? Build.CompareTo(version.Build) : Revision.CompareTo(version.Revision); public override bool Equals(object obj) => obj is VersionCode && Equals((VersionCode)obj); public bool Equals(VersionCode version) => Major == version.Major && Minor == version.Minor && Build == version.Build && Revision == version.Revision; public override int GetHashCode() { var hash = 0; hash |= (Major & 15) << 0x1c; hash |= (Minor & 0xff) << 20; hash |= (Build & 0xff) << 12; hash |= (Revision & 0xfff); return hash; } public static bool operator ==(VersionCode v1, VersionCode v2) => ReferenceEquals(v1, null) ? ReferenceEquals(v2, null) : v1.Equals(v2); public static bool operator !=(VersionCode v1, VersionCode v2) => !(v1 == v2); public static bool operator >(VersionCode v1, VersionCode v2) => v2 < v1; public static bool operator >=(VersionCode v1, VersionCode v2) => v2 <= v1; public static bool operator <(VersionCode v1, VersionCode v2) => !ReferenceEquals(v1, null) && v1.CompareTo(v2) < 0; public static bool operator <=(VersionCode v1, VersionCode v2) => !ReferenceEquals(v1, null) && v1.CompareTo(v2) <= 0; public override string ToString() => Build < 0 ? $"{Major}.{Minor}" : Revision < 0 ? $"{Major}.{Minor}.{Build}" : $"{Major}.{Minor}.{Build}.{Revision}"; } public class VersionCodeConverter : TypeConverter { public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) => sourceType == typeof(ssortingng) || base.CanConvertFrom(context, sourceType); public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) { var version = value as ssortingng; return version != null ? new VersionCode(version) : base.ConvertFrom(context, culture, value); } }