我有一个System.Version
属性的类,如下所示:
当我序列化类时,版本总是空的:
<Version />
Client类看起来像:
[Serializable]
public class Client
{
public string Description;
public string Directory;
public DateTime ReleaseDate;
public Version Version;
}
答案 0 :(得分:16)
System.Version
不可序列化,如果你查看it's properties on MSDN,你会发现它们没有setter ...所以序列化程序不会存储它们。但是,this approach still works。那篇文章(旧的,但仍然有效)提供了一个可序列化的Version类,你可以切换到那个并继续吗?
由tomfanning编辑
我已经从archive.org中删除了死网站上的代码,转载如下。
using System;
using System.Globalization;
namespace CubicOrange.Version
{
/// <summary>
/// Serializable version of the System.Version class.
/// </summary>
[Serializable]
public class ModuleVersion : ICloneable, IComparable
{
private int major;
private int minor;
private int build;
private int revision;
/// <summary>
/// Gets the major.
/// </summary>
/// <value></value>
public int Major
{
get
{
return major;
}
set
{
major = value;
}
}
/// <summary>
/// Gets the minor.
/// </summary>
/// <value></value>
public int Minor
{
get
{
return minor;
}
set
{
minor = value;
}
}
/// <summary>
/// Gets the build.
/// </summary>
/// <value></value>
public int Build
{
get
{
return build;
}
set
{
build = value;
}
}
/// <summary>
/// Gets the revision.
/// </summary>
/// <value></value>
public int Revision
{
get
{
return revision;
}
set
{
revision = value;
}
}
/// <summary>
/// Creates a new <see cref="ModuleVersion"/> instance.
/// </summary>
public ModuleVersion()
{
this.build = -1;
this.revision = -1;
this.major = 0;
this.minor = 0;
}
/// <summary>
/// Creates a new <see cref="ModuleVersion"/> instance.
/// </summary>
/// <param name="version">Version.</param>
public ModuleVersion(string version)
{
this.build = -1;
this.revision = -1;
if (version == null)
{
throw new ArgumentNullException("version");
}
char[] chArray1 = new char[1] { '.' };
string[] textArray1 = version.Split(chArray1);
int num1 = textArray1.Length;
if ((num1 < 2) || (num1 > 4))
{
throw new ArgumentException("Arg_VersionString");
}
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");
}
}
}
}
/// <summary>
/// Creates a new <see cref="ModuleVersion"/> instance.
/// </summary>
/// <param name="major">Major.</param>
/// <param name="minor">Minor.</param>
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;
}
/// <summary>
/// Creates a new <see cref="ModuleVersion"/> instance.
/// </summary>
/// <param name="major">Major.</param>
/// <param name="minor">Minor.</param>
/// <param name="build">Build.</param>
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;
}
/// <summary>
/// Creates a new <see cref="ModuleVersion"/> instance.
/// </summary>
/// <param name="major">Major.</param>
/// <param name="minor">Minor.</param>
/// <param name="build">Build.</param>
/// <param name="revision">Revision.</param>
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
/// <summary>
/// Clones this instance.
/// </summary>
/// <returns></returns>
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
/// <summary>
/// Compares to.
/// </summary>
/// <param name="obj">Obj.</param>
/// <returns></returns>
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
/// <summary>
/// Equalss the specified obj.
/// </summary>
/// <param name="obj">Obj.</param>
/// <returns></returns>
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;
}
/// <summary>
/// Gets the hash code.
/// </summary>
/// <returns></returns>
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);
}
/// <summary>
/// Operator ==s the specified v1.
/// </summary>
/// <param name="v1">V1.</param>
/// <param name="v2">V2.</param>
/// <returns></returns>
public static bool operator ==(ModuleVersion v1, ModuleVersion v2)
{
return v1.Equals(v2);
}
/// <summary>
/// Operator >s the specified v1.
/// </summary>
/// <param name="v1">V1.</param>
/// <param name="v2">V2.</param>
/// <returns></returns>
public static bool operator >(ModuleVersion v1, ModuleVersion v2)
{
return (v2 < v1);
}
/// <summary>
/// Operator >=s the specified v1.
/// </summary>
/// <param name="v1">V1.</param>
/// <param name="v2">V2.</param>
/// <returns></returns>
public static bool operator >=(ModuleVersion v1, ModuleVersion v2)
{
return (v2 <= v1);
}
/// <summary>
/// Operator !=s the specified v1.
/// </summary>
/// <param name="v1">V1.</param>
/// <param name="v2">V2.</param>
/// <returns></returns>
public static bool operator !=(ModuleVersion v1, ModuleVersion v2)
{
return (v1 != v2);
}
/// <summary>
/// Operator <s the specified v1.
/// </summary>
/// <param name="v1">V1.</param>
/// <param name="v2">V2.</param>
/// <returns></returns>
public static bool operator <(ModuleVersion v1, ModuleVersion v2)
{
if (v1 == null)
{
throw new ArgumentNullException("v1");
}
return (v1.CompareTo(v2) < 0);
}
/// <summary>
/// Operator <=s the specified v1.
/// </summary>
/// <param name="v1">V1.</param>
/// <param name="v2">V2.</param>
/// <returns></returns>
public static bool operator <=(ModuleVersion v1, ModuleVersion v2)
{
if (v1 == null)
{
throw new ArgumentNullException("v1");
}
return (v1.CompareTo(v2) <= 0);
}
/// <summary>
/// Toes the string.
/// </summary>
/// <returns></returns>
public override string ToString()
{
if (this.build == -1)
{
return this.ToString(2);
}
if (this.revision == -1)
{
return this.ToString(3);
}
return this.ToString(4);
}
/// <summary>
/// Toes the string.
/// </summary>
/// <param name="fieldCount">Field count.</param>
/// <returns></returns>
public string ToString(int fieldCount)
{
object[] objArray1;
switch (fieldCount)
{
case 0:
{
return string.Empty;
}
case 1:
{
return (this.major.ToString());
}
case 2:
{
return (this.major.ToString() + "." + this.minor.ToString());
}
}
if (this.build == -1)
{
throw new ArgumentException(string.Format("ArgumentOutOfRange_Bounds_Lower_Upper {0},{1}", "0", "2"), "fieldCount");
}
if (fieldCount == 3)
{
objArray1 = new object[5] { this.major, ".", this.minor, ".", this.build };
return string.Concat(objArray1);
}
if (this.revision == -1)
{
throw new ArgumentException(string.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 string.Concat(objArray1);
}
throw new ArgumentException(string.Format("ArgumentOutOfRange_Bounds_Lower_Upper {0},{1}", "0", "4"), "fieldCount");
}
}
}
答案 1 :(得分:12)
我更喜欢使用下面的方法,所以我的类中只有一个Type VersionXml属性。隐式运算符在这里非常有用。
[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 string Value
{
get { return this.Version == null ? string.Empty : this.Version.ToString(); }
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 string ToString()
{
return this.Value;
}
}
答案 2 :(得分:6)
您可以使用字符串代理属性:
[XmlIgnore]
public System.Version Version { get; set; }
[EditorBrowsable(EditorBrowsableState.Never), Browsable(false)]
public string version
{
get
{
if (this.Version == null)
return string.Empty;
else
return this.Version.ToString();
}
set
{
if(!String.IsNullOrEmpty(value))
this.Version = new Version(value);
}
}
答案 3 :(得分:1)
您需要定义get
和set
个访问者,如下:
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
}
);
我得到了这个输出:
<?xml version="1.0" encoding="ibm850"?>
<Version xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Build>111</Build>
<Major>1</Major>
<MajorRevision>0</MajorRevision>
<Minor>1</Minor>
<MinorRevision>10</MinorRevision>
<Revision>10</Revision>
</Version>
答案 4 :(得分:1)
更准确地说,System.Version
不是 XML - 可序列化。 可序列化BinaryFormatter
,例如:
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);
}
答案 5 :(得分:1)
我已经清理了Nick Craver的实现更加简洁和可读,添加了XML序列化支持(使用属性而不是单独的元素),实现了字符串TypeConverter以及修复了一些可能存在NullReferenceExceptions或者NullReferenceExceptions的比较问题。无限循环(从内部调用重载运算符)。
我也使用了一些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<VersionCode>, IEquatable<VersionCode>
{
[XmlAttribute] public int Major { get; private set; }
[XmlAttribute] public int Minor { get; private set; }
[XmlAttribute] public int Build { get; private set; } = -1;
[XmlAttribute] 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<string>(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(string)
|| base.CanConvertFrom(context, sourceType);
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
var version = value as string;
return version != null
? new VersionCode(version)
: base.ConvertFrom(context, culture, value);
}
}