AppVersion Struct & VersionParse Exception I am working on an app that will interact with assembly (app) versions. I created a struct for that, along with an exception for parsing error.

Here's the code:

    [Serializable]
    public class VersionParseException : Exception
    {
        public VersionParseException()
        { }

        public VersionParseException(string message)
            : base(message)
        { }

        public VersionParseException(string message, Exception innerException)
            : base(message, innerException)
        { }

        protected VersionParseException(SerializationInfo info, StreamingContext context)
            : base(info, context)
        { }

    }

    public struct AppVersion
    {
        int _majorVersion;
        public int MajorVersion
        {
            get { return _majorVersion; }
            set
            {
                _majorVersion = value;
            }
        }

        int _minorVersion;
        public int MinorVersion
        {
            get { return _minorVersion; }
            set
            {
                _minorVersion = value;
            }
        }

        int _buildNumber;
        public int BuildNumber
        {
            get { return _buildNumber; }
            set
            {
                _buildNumber = value;
            }
        }

        int _revision;
        public int Revision
        {
            get { return _revision; }
            set
            {
                _revision = value;
            }
        }

        public string Version
        {
            get { return MajorVersion.ToString() + "." + MinorVersion.ToString() + "." + BuildNumber.ToString() + "." + Revision.ToString(); }
            set
            {
                try
                {
                    MajorVersion = int.Parse(value.Split('.')[0]);
                    MinorVersion = int.Parse(value.Split('.')[1]);
                    BuildNumber = int.Parse(value.Split('.')[2]);
                    Revision = int.Parse(value.Split('.')[3]);
                }
                catch (Exception exception)
                {
                    throw new VersionParseException("Invalid App Version", exception);
                }
            }
        }
    }


Is there any better way to handle AppVersions and exceptions occurring in the process of using it?

And here's an example of using the struct:

AppVersion version1;
version1.Version = "0.500.965.201";
Console.WriteLine(version1.MinorVersion); // outputs "500"
version1.BuildNumber = 753;
Console.WriteLine(version1.Version);      // outputs "0.500.753.201"


Another example on throwing the exception:

AppVersion version2;
version2.Version = "0.blabla.987.test"; //Throws VersionParseException
I am working on an app that will interact with assembly (app) versions


There's a class, System.Version, that might be suitable for your needs. System.Version:


  Represents the version number of an assembly, operating system, or the common language runtime.


It has Major, Minor, Build, and Revision properties.

If you still want to roll your own, my advice is to


Make AppVersion immutable
Be stricter about the values you allow
Implement IEquatable&lt;AppVersion&gt;
Consider implementing IComparable&lt;AppVersion&gt;




In general, you should avoid mutable structs.

From MSDN


  X DO NOT define mutable value types.
  
  Mutable value types have several problems. For example, when a property getter returns a value type, the caller receives a copy. Because the copy is created implicitly, developers might not be aware that they are mutating the copy, and not the original value.


See also: Why are mutable structs “evil”?



With the code as written, this works just fine:

appVersion.Version = "   +123 . -4236 . +0 . -789";


Use the overloads of int.Parse/int.TryParse that take a NumberStyles argument. If you provide constructors as suggested below, check that the values passed in are non-negative.



From MSDN


  ✓ DO implement IEquatable&lt;T&gt; on value types.
  
  The Object.Equals method on value types causes boxing, and its default implementation is not very efficient, because it uses reflection. Equals can have much better performance and can be implemented so that it will not cause boxing.




I find it hard to imagine not ever wanting to compare app versions, so you will probably want to implement IComparable&lt;AppVersion&gt;.



I would recommending getting rid of the Version property entirely. Instead, provide one or more constructors like

public AppVersion(int majorVersion, int minorVersion)

public AppVersion(int majorVersion, int minorVersion, int buildNumber)

...


and then provide static methods AppVersion Parse(string) and bool TryParse(string, out AppVersion).



Also, you should be aware of the existence of auto-implemented properties.