C#: Compare Application Version Numbers


UPDATE: As discussed in the comments, 99% of the time using the System.Version class included in the .net Framework will suffice for comparing application version numbers. Documentation for this can be found here. The below post will help you if for some reason (ex. you use commas instead of periods to separate the version number) the System.Version class will not work

When incorporating an automatic update feature into an application, one of the things that you will need to do is compare the installed version number to the currently available version number. Given version numbers of the format ‘X.X.X.X’ I have seen some people suggest simply removing the periods, converting the string to an integer and doing a simple comparison of the integers. Such a solution works great if you have complete control over the format of the version number and you can ensure the number of digits per grouping stays the same. But, suppose you have the following two version numbers: 1.4.0 and 1.1.28. Following the logic explained above, you will be comparing the integers 140 and 1128 and the second version will be determined to be greater than the first, which is incorrect.

In order to alleviate this problem, I have created the following method below to correctly compare two version numbers. This method uses the SplitToList extension which takes a string, splits it based on a given string and then converts each element to the specified type. You can find a more detailed explanation and the code here.

public static int CompareVersionNumbers(string versionA, string versionB)
{           
    // Convert each version numbers string to a list of integers
    List<int> a = versionA.SplitToList<int>(".");
    List<int> b = versionB.SplitToList<int>(".");            
   
    // Ensure that each of the lists are the same length
    while(a.Count < b.Count) { a.Add(0); }
    while(b.Count < a.Count) { b.Add(0); }

    // Compare elements of each list
    for (int i = 0; i < a.Count; i++)
    {
        // If the element from list A is greater than B, 
        // versionA is greater than versionB and visa versa.
        // If they are equal, go to the next element.
        if (a[i] > b[i])
            return 1;
        else if (b[i] > a[i])
            return -1;
    }

    // If we reach this point, the versions are equal
    return 0;
}

C#: String to Integer, Decimal, Float, or Any Type of Array or List


The string.Split method is a great tool that can be used when manipulating strings. But, this method simply returns an array of strings when frequently I need a collection returned in the type that the strings actually represent. To fix this you simply have to loop through each item in the string array and convert it to its representative type. For example, if you are reading in a comma delimited file of temperatures, you can split on the commas and then loop through the returned array, parsing each element and adding it to a new list, as follows:


string temperatures = "67.2,92.1,78.2,100.3,89.2";

string[] tempArray = temperatures.Split(',');

List<float> temps = new List<float>();
foreach (string temp in tempArray)
    temps.Add(float.Parse(temp));

While such a solution is common and quite acceptable, I wanted to make it simpler and reusable. To do such, I decided to implement the above logic in a generic extension method.


/// <summary>
/// Splits a string using the supplied separator and casts each element to the
/// indicated type.
/// </summary>
/// <typeparam name="T">The type of the List to return</typeparam>        
/// <param name="s">The string on which the operation will be performed.</param>
/// <param name="separator">An array of strings that delimit the substrings in this string, an empty
///     array that contains no delimiters, or null.</param>
/// <returns>A List of type T containing the elements formed after splitting the string using
/// the given separators.</returns>
public static List<T> SplitToList<T>(this string s, params string[] separator)
{
    return s.SplitToList<T>(StringSplitOptions.None, separator);
}

/// <summary>
/// Splits a string using the supplied separator and casts each element to the
/// indicated type.
/// </summary>
/// <typeparam name="T">The type of the List to return</typeparam>        
/// <param name="s">The string on which the operation will be performed.</param>
/// <param name="options">Specify System.StringSplitOptions.RemoveEmptyEntries to omit empty array
///     elements from the array returned, or System.StringSplitOptions.None to include
///     empty array elements in the array returned.</param>
/// <param name="separator">An array of strings that delimit the substrings in this string, an empty
///     array that contains no delimiters, or null.</param>
/// <returns>A List of type T containing the elements formed after splitting the string using
/// the given separators.</returns>
public static List<T> SplitToList<T>(this string s, StringSplitOptions options, params string[] separator)
{
    // Split the string based on the supplied separators
    string[] array = s.Split(separator, options);
    
    List<T> values = new List<T>();

    // Convert each element in the array to the indicated type
    foreach (string element in array)
        values.Add((T)Convert.ChangeType(element, typeof(T)));                

    return values;
}

Now our temperature example can be reduced to the following:


string temperatures = "67.2,92.1,78.2,100.3,89.2";
List<float> temps = temperatures.SplitToList<float>(",");

Below are some other examples of how this extension method could be used:

string s1 = "true-false-true-true-true-false";
List<bool> bools = s1.SplitToList<bool>("-");

string s2 = "a b c d e f g h i j";
List<char> chars = s2.SplitToList<char>(" ");

// Split on both commas and periods
string s3 = "1,3,4.5.7,1.4,6.7,8.2";
List<int> ints = s3.SplitToList<int>(",", ".");

C#: String Concatenation using StringBuilder and LINQ Aggregate Function


I always forget how to do this so I thought I would post it mainly for my reference.

List<string> nameList = new List<string>() { "Roger", "Clark", "Wonda", "Anita" };

// A useless Select call in this instance just to remind you
// that you coulde use LINQ to select a set of strings
// from a list of objects
StringBuilder names = nameList.Select(n => n)
                              .Aggregate(new StringBuilder(), (current, next) => current.Append(next).Append(", "));

// Remove the trailing comma and space
if (names.Length > 1)
    names.Remove(names.Length - 2, 2);

Console.WriteLine(names.ToString());

// Output
// ------
// Roger, Clark, Wonda, Anita

C#: DateTime.ToString() Format – Apostrophe Before the Year


I was trying to use the DateTime.ToString(string) method to create a string that had the abbreviated month and last two digits of the year but I wanted to add an apostrophe before the year to produce something like Sep ’10 for September 2010. It took me a while to figure our the correct escaping sequence but here it is.

DateTime date = DateTime.Today;
Console.WriteLine(date.ToString("MMM \"'\"yy"));

// Output
// ------
// Sep '10

Any text between the two escaped quotation marks (\”…\”) will be printed as literal text.

C#: Random Text Generator


Whenever I need to generate random text I generally just Google ‘Random Text’ and pull up the first or second site in the list. This works great when you can copy and paste the text from your browser, but I ran across a situation where I needed to generate some random text from within one of my applications. So, I whipped up a small method that generated a random string of a given length and continued on my way. But, soon thereafter the inner programmer got the better of me and I just had to turn the simple method into an entire class that aided in random text generation.

The RandomText class that I created allows you to generate random strings (words), sentences, and paragraphs. Each method is overloaded with parameters that allow you to specify things like the possible word lengths that make up each sentence and the possible sentence lengths that make up each paragraph. Additionally there are methods that take no parameters and will generate a random string (word), sentence, or paragraph using default possible lengths. There are also options for adding punctuation to the sentences include middle of the sentence punctuation like commas and end of sentence punctuation like periods.

I have included the public properties and methods along with their documentation below. The actual source code can be found on codeplex here.

public class RandomText
{  
        /// <summary>
        /// Indicate whether or not to include random middle of the sentance punctuation
        /// marks in generated sentances
        /// </summary>
        public bool AddMiddleOfSentancePunctuationMarks = false;

        /// <summary>
        /// Indicates whether or not to add an end of sentance punctuation mark
        /// </summary>
        public bool AddEndOfSentancePunctuation = true;
      
        public RandomText()                

        /// <summary>
        /// Generates a random string of a specfic length.
        /// </summary>        
        /// <returns>Returns a randomly generated string (lower case) of a specific length.</returns>
        public string String()  

        /// <summary>
        /// Generates a random string of a specfic length.
        /// </summary>
        /// <param name="length">The length of the random string to generate.</param>        
        /// <returns>Returns a randomly generated string (lower case) of a specific length.</returns>
        public string String(int length)

        /// <summary>
        /// Generates a random string of a specfic length.
        /// </summary>
        /// <param name="length">The length of the random string to generate.</param>
        /// <param name="randomCharacterCase">If true, each character in the string will have
        /// an equal chance of being either upper case or lower case.  If false, the generated
        /// string will be all lower case.
        /// </param>
        /// <returns>Returns a randomly generated string of a specific length.</returns>
        public string String(int length, bool randomCharacterCase)

        /// <summary>
        /// Returns a random number within a specified range.
        /// </summary>
        /// <param name="minValue">The inclusive lower bound of the random number returned.</param>        
        /// <param name="maxValue">The exclusive upper bound of the random number returned. maxValue must be
        ///  greater than or equal to minValue.</param>               
        /// <returns>A 32-bit signed integer greater than or equal to minValue and less than maxValue;
        ///  that is, the range of return values includes minValue but not maxValue. If
        ///  minValue equals maxValue, minValue is returned.</returns>
        private int Number(int minValue, int maxValue)
		
        /// <summary>
        /// Generates a random sentance.
        /// </summary>        
        /// <returns>Returns a random sentance of random length and words from the default sentance and word lengths.</returns>
        public string Sentance()   

        /// <summary>
        /// Generates a random sentance of a given number of words .
        /// </summary>
        /// <param name="numberOfWords">The number of words in the sentance</param>
        /// /// <returns>Returns a random sentance of the specified length.</returns>
        public string Sentance(int numberOfWords)     

        /// <summary>
        /// Generates a random sentance of a given number of words and possible word lengths.
        /// </summary>
        /// <param name="numberOfWords">The number of words in the sentance</param>
        /// <param name="possibleWordLengths">An array of integers representing the possible number of characters in each word</param>
        /// <returns>Returns a string containing a specified number of random words composed of random characters</returns>
        public string Sentance(int numberOfWords, int[] possibleWordLengths)       

        /// <summary>
        /// Generates a random paragraph.
        /// </summary>
        public string Paragraph()        

        /// <summary>
        /// Generates a random paragraph of a given number of sentances.
        /// </summary>
        /// <param name="numberOfSentances">The number of sentances in the paragraph.</param>
        public string Paragraph(int numberOfSentances)     

        /// <summary>
        /// Generates a random paragraph of a given number of sentances.
        /// </summary>
        /// <param name="numberOfSentances">The number of sentances in the paragraph.</param>
        /// <param name="possibleSentanceLengths">An array of integers representing the possible number of words in each sentance.</param>
        public string Paragraph(int numberOfSentances, int[] possibleSentanceLengths)       

        /// <summary>
        /// Generates a random paragraph of a given number of sentances.
        /// </summary>
        /// <param name="numberOfSentances">The number of sentances in the paragraph.</param>
        /// <param name="possibleSentanceLengths">An array of integers representing the possible number of words in each sentance.</param>
        /// <param name="possibleWordLengths">An array of integers representing the possible number of characters in each word</param>
        /// <returns>Returns a string containing a specified number of random sentances composed of random words and characters</returns>
        public string Paragraph(int numberOfSentances, int[] possibleSentanceLengths, int[] possibleWordLengths)        
    }
Follow

Get every new post delivered to your Inbox.

Join 66 other followers