Monday, February 9, 2009

UK Common regular expressions

I thought I would share my ideas on regular expressions. What I don’t like about the RegularExpressionValidator is that you have to repeat your regular expressions over and over again. It would be so much better if you could place them in a single place. So I thought I would write about a solution I came up with a few years ago. So the first part is the list of Regular Expressions. I like the idea of putting them in their own config file.

The section allows us to have our own class that represents regular expressions. The interesting parts of the regular expressions are

  • The & is represented as a a escaped & as it is in XML
  • We only have to define things like FirstName once and if the customer changes their mind, we change it in one place.
  • The password is minimum of 6 in length and must have an upper case, a lower case and one digit.
  • Most of the regular expressions allow for é and á and various other common accents
  • The post code has gone through lots of testing with customers and is the best I have found.
  • The phone numbers are UK
<regexSection>
<
regularExpressions>
<
regexConfig name="Password" value="^.*(?=.{6,})(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).*$" />
<
regexConfig name="FirstName" value="^[a-z A-Z \xc0-\xd6 \xd8-\xf6 \xf9-\xff'-]{2,50}$" />
<
regexConfig name="LastName" value="^[a-z A-Z \xc0-\xd6 \xd8-\xf6 \xf9-\xff'-]{2,50}$" />
<
regexConfig name="PhoneNumber" value="^(?=.{10,13}$)0([0-9] ?){8,9}[0-9]$" />
<
regexConfig name="MobilePhoneNumber" value="^(?=.{11,13}$)07([0-9] ?){8}[0-9]$" />
<
regexConfig name="Email" value="(?i)^[a-z0-9!#$%&amp;'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&amp;'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+(?:[A-Z]{2}|com|org|net|gov|biz|info|name|aero|jobs|museum|asia|edu)\b" />
<
regexConfig name="JobTitle" value="^[a-z A-Z&amp;)( \xc0-\xd6 \xd8-\xf6 \xf9-\xff'-]{2,50}$" />
<
regexConfig name="Text" value="^[a-z A-Z \xc0-\xd6 \xd8-\xf6 \xf9-\xff'-]{2,50}$" />
<
regexConfig name="Text100" value="^[a-z A-Z&amp;!. 0-9 \xc0-\xd6 \xd8-\xf6 \xf9-\xff'-]{2,100}$" />
<
regexConfig name="Text1000" value="^[a-z A-Z&amp;!. 0-9 \xc0-\xd6 \xd8-\xf6 \xf9-\xff'-]{2,1000}$" />
<
regexConfig name="AlphaNumeric" value="^[0-9a-z A-Z \xc0-\xd6 \xd8-\xf6 \xf9-\xff]+$" />
<
regexConfig name="BuildingName" value="^[0-9a-z A-Z' \xc0-\xd6 \xd8-\xf6 \xf9-\xff.,-]+[-]*[0-9a-z A-Z' \xc0-\xd6 \xd8-\xf6 \xf9-\xff.,-]*$" />
<
regexConfig name="Street" value="^[a-z A-Z' \xc0-\xd6 \xd8-\xf6 \xf9-\xff.,-]+$" />
<
regexConfig name="Address" value="^[a-z A-Z-' \xc0-\xd6 \xd8-\xf6 \xf9-\xff.]+$" />
<
regexConfig name="Postcode" value="(?i)^(((([A-PR-UWYZ][0-9][0-9]?)|(([A-PR-UWYZ][A-HK-Y][0-9][0-9]?)|(([A-PR-UWYZ][0-9][A-HJKSTUW])|([A-PR-UWYZ][A-HK-Z][0-9][ABEHMNPRVWXY]))))\s?[0-9][ABD-HJLNP-UW-Z]{2})|(GIR\s?0AA))$" />
<
regexConfig name="POBox" value="(?i)^((?!PO Box|POBox|P.O. Box|P.O.Box|P.O Box|PO. Box).)*$" />
<
regexConfig name="AccountNumber" value="^[0-9]{8}$" />
<
regexConfig name="EmployerName" value="^[0-9a-z A-Z\xc0-\xd6 \xd8-\xf6 \xf9-\xff'-]+$" />
<
regexConfig name="SortCode" value="^[0-9]{2}$" />
<
regexConfig name="Income" value="^(0|[1-9]{1}(,[0-9]{3}){0,2}|[1-9]{1}[0-9]{0,2}(,[0-9]{3})?|[1-9]{1}[0-9]{0,6})$" />
<
regexConfig name="Expenditure" value="^([1-9]{1}(,[0-9]{3}){0,2}|[1-9]{1}[0-9]{0,2}(,[0-9]{3})?|[1-9]{1}[0-9]{0,6})$" />
<
regexConfig name="InternetID" value="^[a-z A-Z \xc0-\xd6 \xd8-\xf6 \xf9-\xff'-]{6,13}$" />
<
regexConfig name="MemorableWord" value="^[a-zA-Z0-9'-]{6,20}$" />
<
regexConfig name="PIN" value="^[0-9]{5,5}$" />
<
regexConfig name="Decimal" value="^[0-9]+$" />
<
regexConfig name="DDMMYYYY" value="^((((0?[1-9]|[12]\d|3[01])(0?[13578]|1[02])((1[6-9]|[2-9]\d)?\d{2}))|((0?[1-9]|[12]\d|30)(0?[13456789]|1[012])((1[6-9]|[2-9]\d)?\d{2}))|((0?[1-9]|1\d|2[0-8])0?2((1[6-9]|[2-9]\d)?\d{2}))|(290?2((1[6-9]|[2-9]\d)?(0[48]|[2468][048]|[13579][26])|((16|[2468][048]|[3579][26])00)|00)))|(((0[1-9]|[12]\d|3[01])(0[13578]|1[02])((1[6-9]|[2-9]\d)?\d{2}))|((0[1-9]|[12]\d|30)(0[13456789]|1[012])((1[6-9]|[2-9]\d)?\d{2}))|((0[1-9]|1\d|2[0-8])02((1[6-9]|[2-9]\d)?\d{2}))|(2902((1[6-9]|[2-9]\d)?(0[48]|[2468][048]|[13579][26])|((16|[2468][048]|[3579][26])00)|00))))$"/>
<
regexConfig name="SubmissionName" value="^[a-z A-Z&amp;!)(# 0-9 \xc0-\xd6 \xd8-\xf6 \xf9-\xff'-]{2,100}$" />
</
regularExpressions>
</
regexSection>

Sunday, February 8, 2009

Query String Utilities

Every time I write any web layer code, I always end up have to manipulate query strings and this little class pays dividends when manipulating the Query String

Uri mainUrl = . . . 
QueryStringCollection queryString = new QueryStringCollection(mainUrl.Query);
queryString.Add("BookingEventId", bookingEventId.ToString());

So here is the class, it has indexers, contains, to strings and will automatically Url encode.

/// <summary>
///
A chainable query string helper class.
/// </summary>
/// <example>
///
string strQuery = QueryString.Current.Add("id", "179").ToString();
/// string strQuery = new QueryString().Add("id", "179").ToString();
/// </example>
[SuppressMessage("Microsoft.Design", "CA1035:ICollectionImplementationsHaveStronglyTypedMembers",
Justification="We are implementing a new object based collection."), Serializable]
public class QueryStringCollection : NameValueCollection
{
public QueryStringCollection() { }

/// <summary>
///
Initializes a new instance of the <see cref="QueryStringCollection"/> class.
/// </summary>
/// <param name="info">
A <see cref="T:System.Runtime.Serialization.SerializationInfo"/> object that contains the information required to serialize the new <see cref="T:System.Collections.Specialized.NameValueCollection"/> instance.</param>
/// <param name="context">
A <see cref="T:System.Runtime.Serialization.StreamingContext"/> object that contains the source and destination of the serialized stream associated with the new <see cref="T:System.Collections.Specialized.NameValueCollection"/> instance.</param>
protected QueryStringCollection(SerializationInfo info, StreamingContext context)
: base(info, context)
{
}

/// <summary>
///
Initializes a new instance of the <see cref="QueryStringCollection"/> class.
/// </summary>
/// <param name="queryString">
The query string.</param>
public QueryStringCollection(string queryString)
{
FillFromString(queryString);
}

/// <summary>
///
Gets the current.
/// </summary>
/// <value>
The current.</value>
public static QueryStringCollection Current
{
get
{
return new QueryStringCollection().FromCurrent();
}
}

/// <summary>
///
Extracts the query string.
/// </summary>
/// <param name="value">
The value.</param>
/// <returns></returns>
public static string ExtractQueryString(string value)
{
if (!string.IsNullOrEmpty(value))
{
if (value.Contains("?"))
return value.Substring(value.IndexOf("?", StringComparison.OrdinalIgnoreCase) + 1);
}
return value;
}

/// <summary>
///
Fills from string.
/// </summary>
/// <param name="value">
The value.</param>
/// <returns></returns>
public QueryStringCollection FillFromString(string value)
{
base.Clear();
if (string.IsNullOrEmpty(value)) return this;
foreach (string keyValuePair in ExtractQueryString(value).Split('&'))
{
if (string.IsNullOrEmpty(keyValuePair)) continue;
string[] split = keyValuePair.Split('=');
base.Add(split[0],
split.Length == 2 ? split[1] : "");
}
return this;
}

/// <summary>
///
returns a QueryString object based on the current querystring of the request
/// </summary>
/// <returns>
the QueryString object </returns>
public QueryStringCollection FromCurrent()
{
if (HttpContext.Current != null)
{
return FillFromString(HttpContext.Current.Request.QueryString.ToString());
}
base.Clear();
return this;
}

/// <summary>
///
add a name value pair to the collection
/// </summary>
/// <param name="name">
the name</param>
/// <param name="value">
the value associated to the name</param>
/// <returns>
the QueryString object </returns>
public new QueryStringCollection Add(string name, string value)
{
return Add(name, value, false);
}

/// <summary>
///
adds a name value pair to the collection
/// </summary>
/// <param name="name">
the name</param>
/// <param name="value">
the value associated to the name</param>
/// <param name="isUnique">
true if the name is unique within the querystring. This allows us to override existing values</param>
/// <returns>
the QueryString object </returns>
public QueryStringCollection Add(string name, string value, bool isUnique)
{
string existingValue = base[name];
if (string.IsNullOrEmpty(existingValue))
base.Add(name, HttpUtility.UrlEncodeUnicode(value));
else if (isUnique)
base[name] = HttpUtility.UrlEncodeUnicode(value);
else
base
[name] += "," + HttpUtility.UrlEncodeUnicode(value);
return this;
}

/// <summary>
///
removes a name value pair from the querystring collection
/// </summary>
/// <param name="name">
name of the querystring value to remove</param>
/// <returns>
the QueryString object</returns>
public new QueryStringCollection Remove(string name)
{
string existingValue = base[name];
if (!string.IsNullOrEmpty(existingValue))
base.Remove(name);
return this;
}

/// <summary>
///
clears the collection
/// </summary>
/// <returns>
the QueryString object </returns>
public QueryStringCollection Reset()
{
base.Clear();
return this;
}

/// <summary>
///
Encrypts the keys and values of the entire querystring acc. to a key you specify
/// </summary>
/// <returns>
an encrypted querystring object</returns>
public QueryStringCollection Encrypt()
{
QueryStringCollection qs = new QueryStringCollection();
for (var i = 0; i < base.Keys.Count; i++)
{
if (!string.IsNullOrEmpty(base.Keys[i]))
{
foreach (string val in base[base.Keys[i]].Split(','))
qs.Add(base.Keys[i].Encrypt(), HttpUtility.UrlDecode(val).Encrypt());
}
}
return qs;
}

/// <summary>
///
Decrypts the keys and values of the entire querystring acc. to a key you specify
/// </summary>
/// <returns>
a decrypted querystring object</returns>
public QueryStringCollection Decrypt()
{
QueryStringCollection qs = new QueryStringCollection();
for (var i = 0; i < base.Keys.Count; i++)
{
if (!string.IsNullOrEmpty(base.Keys[i]))
{
foreach (string val in base[base.Keys[i]].Split(','))
qs.Add(HttpUtility.UrlDecode(base.Keys[i]).Decrypt(), HttpUtility.UrlDecode(val).Decrypt());
}
}
return qs;
}

/// <summary>
///
overrides the default
/// </summary>
/// <param name="name"></param>
/// <returns>
the associated decoded value for the specified name</returns>
public new string this[string name]
{
get
{
return HttpUtility.UrlDecode(base[name]);
}
}

/// <summary>
///
overrides the default indexer
/// </summary>
/// <param name="index"></param>
/// <returns>
the associated decoded value for the specified index</returns>
public new string this[int index]
{
get
{
return HttpUtility.UrlDecode(base[index]);
}
}

/// <summary>
///
checks if a name already exists within the query string collection
/// </summary>
/// <param name="name">
the name to check</param>
/// <returns>
a boolean if the name exists</returns>
public bool Contains(string name)
{
string existingValue = base[name];
return !string.IsNullOrEmpty(existingValue);
}

/// <summary>
///
outputs the querystring object to a string
/// </summary>
/// <returns>
the encoded querystring as it would appear in a browser</returns>
public override string ToString()
{
StringBuilder builder = new StringBuilder();
for (var i = 0; i < base.Keys.Count; i++)
{
if (!string.IsNullOrEmpty(base.Keys[i]))
{
foreach (string val in base[base.Keys[i]].Split(','))
builder.Append((builder.Length == 0) ? "?" : "&").Append(HttpUtility.UrlEncodeUnicode(base.Keys[i])).Append("=").Append(val);
}
}
return builder.ToString();
}
}

Guid.TryParse()

Are you ever passed GUID’s via a query string? How can you trust that it is a real GUID? I want to be able to do this

Guid result;
if (GuidHelper.TryParse(Request["ID"], out result))
return result;
else
return null
;


I have to parse Guids occasionally so I wrote this little helper to add to where the .Net Framework is lacking.



public static class GuidHelper
{
private static Regex guidFormat = new Regex(
"^[A-Fa-f0-9]{32}$|" +
"^({|\\()?[A-Fa-f0-9]{8}-([A-Fa-f0-9]{4}-){3}[A-Fa-f0-9]{12}(}|\\))?$|" +
"^({)?[0xA-Fa-f0-9]{3,10}(, {0,1}[0xA-Fa-f0-9]{3,6}){2}, {0,1}({)([0xA-Fa-f0-9]{3,4}, " +
"{0,1}){7}[0xA-Fa-f0-9]{3,4}(}})$",
RegexOptions.Compiled|RegexOptions.CultureInvariant|RegexOptions.Singleline);


/// <summary>
///
Converts the string representation of a Guid to its Guid
/// equivalent. A return value indicates whether the operation
/// succeeded.
/// </summary>
/// <param name="value">
A string containing a Guid to convert.</param>
/// <param name="result">
///
When this method returns, contains the Guid value equivalent to
/// the Guid contained in <paramref name="value"/>, if the conversion
/// succeeded, or <see cref="Guid.Empty"/> if the conversion failed.
/// The conversion fails if the <paramref name="value"/> parameter is a
/// <see langword="null" /> reference (<see langword="Nothing" /> in
/// Visual Basic), or is not of the correct format.
/// </param>
/// <value>
/// <see langword="true" />
if <paramref name="value"/> was converted
/// successfully; otherwise, <see langword="false" />.
/// </value>
/// <exception cref="ArgumentNullException">
///
Thrown if <pararef name="value"/> is <see langword="null"/>.
/// </exception>
public static bool TryParse(string value, out Guid result)
{
if (!string.IsNullOrEmpty(value))
{
Match match = guidFormat.Match(value);
if (match.Success)
{
result = new Guid(value);
return true;
}
}
result = Guid.Empty;
return false;
}
}

Triple DES Encrypt/decrypt extension method

I wanted to have a simple encryption method so that I could convert any string.
return credentials.Encrypt();


You should note that there is no constructor as it is better to initialise our key with a function call.


/// <summary>
///
The class will encrypt or decrpyt based on Triple DES algoritm
/// </summary>
public static class EncryptionService
{
static byte[] _encryptionKey = InitialiseKey();

/// <summary>
///
Initialises the key.
/// </summary>
/// <returns></returns>
private static byte[] InitialiseKey()
{
string encryptionKey = ConfigurationManager.AppSettings["EncryptionPassword"];
if (string.IsNullOrEmpty(encryptionKey))
throw new ConfigurationErrorsException(
"'EncryptionPassword' is not defined in your config file."
);

byte[] encryptionKeyBytes = ASCIIEncoding.ASCII.GetBytes(encryptionKey);

using (MD5CryptoServiceProvider hashmd5 = new MD5CryptoServiceProvider())
{
return hashmd5.ComputeHash(encryptionKeyBytes);
}
}

/// <summary>
///
Decrypts the specified input.
/// </summary>
/// <param name="input">
The input.</param>
/// <returns></returns>
public static string Decrypt(this string input)
{
if (string.IsNullOrEmpty(input))
return string.Empty;

using (TripleDESCryptoServiceProvider des = new TripleDESCryptoServiceProvider())
{
des.Key = _encryptionKey;
des.Mode = CipherMode.ECB;

byte[] buff = null;
try
{
buff = Convert.FromBase64String(input);
}
catch (FormatException)
{
return string.Empty;
}

return ASCIIEncoding.ASCII.GetString(
des.CreateDecryptor().TransformFinalBlock(buff, 0, buff.Length));
}
}

/// <summary>
///
Encrypts the specified input.
/// </summary>
/// <param name="input">
The input.</param>
/// <returns></returns>
public static string Encrypt(this string input)
{
using (TripleDESCryptoServiceProvider des = new TripleDESCryptoServiceProvider())
{
des.Key = _encryptionKey;
des.Mode = CipherMode.ECB;

byte[] buff = ASCIIEncoding.ASCII.GetBytes(input);

return Convert.ToBase64String(
des.CreateEncryptor().TransformFinalBlock(buff, 0, buff.Length));
}
}
}

Formatted Code in a blog

I realised that over the years I have never blogged any of my work as I never had time. So now I intend to address this matter and place little utilities and snippets up for other people. First I wanted to make all of my code look nice and neat, so I started looking at the following blog.


But then I found this little add-in

Tuesday, November 4, 2008

Using dictionaries for constant Identifiers

I wanted to have a constant string so that I could have a list of roles, however I also wanted to have a friendly description, so how do you go about this? The reason for using a constant string is so that we are consistent when we are checking our roles. e.g.
if (_user.IsInRole(Role.Practitioner))
{
. . .
}

But what happens when you want to get a friendly description too? Well firstly I wanted to be able to put all the roles I had defined into a drop down list, so it would be nice if all the roles were defined in one place. So I wanted to be able to do this

// Put the roles in the role dropdownlist
RoleDropDownList.DataSource = Role.Roles;
RoleDropDownList.DataTextField = "Value";
RoleDropDownList.DataValueField = "Key";
RoleDropDownList.DataBind();
RoleDropDownList.Items.Insert(0, new ListItem("All", ""));

So how do we do it? Simply use a dictionary. Have the key be the constant string and the value a friendly description. Now the important point to note here is that we could be tempted to use StringDictionary as it is a specialization of a Dictionary, but if you look carefully in the documentation, the key will be converted to a lower case string and that *is not what we want*.

/// <summary>
///
These are the membership roles that users can have
/// </summary>
public static class Role
{
/// <summary>A basic user (frozen user)</summary>
public const string Basic = "Basic";

/// <summary>A standard practitioner</summary>
public const string Practitioner = "Practitioner";

/// <summary>An IP administrator</summary>
public const string Administrator = "Administrator";

/// <summary>A training manager</summary>
public const string TrainingManager = "TrainingManager";

/// <summary>A submissions manager</summary>
public const string SubmissionManager = "SubmissionManager";

/// <summary>A submission assessor</summary>
public const string Assessor = "Assessor";

public const string Mentor = "Mentor";

/// <summary>
///
Create a friendly description of each role
/// </summary>
public static Dictionary<String, String> Roles
= new Dictionary<String, String>()
{
{ Basic, "Frozen User" },
{ Practitioner, "Practitioner" },
{ Administrator, "Administrator" },
{ TrainingManager, "Training Manager" },
{ SubmissionManager, "Submission Manager" },
{ Assessor, "Assessor"},
{ Mentor, "Mentor"}
};
}

Wednesday, September 10, 2008

Enum Parsing

I was getting so frustrated with writing this
ViewMode viewType = (ViewMode)Enum.Parse(typeof(ViewMode), value);

all the time, so I created a class so I can do

ViewMode viewType = EnumParser.Parse<ViewMode>(value);

but the came along extension methods and now we can then do

ViewMode viewType = value.ParseEnum<ViewMode>();

then lastly wouldn't it be cool to have the default value if you can't parse it?

ViewMode viewType = value.GetEnumOrDefault<ViewMode>(ViewMode.None);

so here is the class. There is also some goodies so that you can decorate your enum's with attributes and then GetDescription to have a friendly version for them!

/// <summary>
///
Helpful helper class for all things with enumerations
/// </summary>
public static class EnumParser
{
/// <summary>
///
Parses the specified enum value - ignoring case.
/// </summary>
/// <param name="enumValue">
The enum value.</param>
/// <returns></returns>
[SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")]
public static T Parse<T>(string enumValue)
{
return Parse<T>(enumValue, true);
}

/// <summary>
///
Parses the specified enum value.
/// </summary>
/// <param name="enumValue">
The enum value.</param>
/// <param name="ignoreCase">
if set to <c>true</c> [ignore case].</param>
/// <returns></returns>
[SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")]
public static T Parse<T>(string enumValue, bool ignoreCase)
{
if (string.IsNullOrEmpty(enumValue))
throw new ArgumentNullException("enumValue", CoreResources.NullValue);

enumValue = enumValue.Trim();

Type t = typeof(T);

if (!t.IsEnum)
throw new ArgumentException(CoreResources.InvalidType, "enumValue");

return (T)Enum.Parse(t, enumValue, ignoreCase);
}

/// <summary>
///
Parses the enum.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="value">
The value.</param>
/// <returns></returns>
[SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")]
public static T ParseEnum<T>(this string value)
{
if (string.IsNullOrEmpty(value))
throw new ArgumentNullException("value", CoreResources.NullValue);

return ParseEnum<T>(value, false);
}

/// <summary>
///
Parses the enum.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="value">
The value.</param>
/// <param name="ignoreCase">
if set to <c>true</c> [ignore case].</param>
/// <returns></returns>
[SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")]
public static T ParseEnum<T>(this string value, bool ignoreCase)
{
if (string.IsNullOrEmpty(value))
throw new ArgumentNullException("value", CoreResources.NullValue);

return Parse<T>(value, ignoreCase);
}

/// <summary>
///
Gets the enum or default.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="value">
The value.</param>
/// <param name="defaultValue">
The default value.</param>
/// <returns></returns>
[SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")]
[SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes",
Justification = "Never throw the exception in this case")]
public static T GetEnumOrDefault<T>(this string value, T defaultValue)
{
if (string.IsNullOrEmpty(value))
return defaultValue;

try
{
return Parse<T>(value, true);
}
catch
{
return defaultValue;
}
}

/// <summary>
///
Tries to parse the enum. Case insensitive. Returns true/false for errors (or return InvalidArgumentException?)
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="value">
The value.</param>
/// <param name="enumInstance">
The enum instance.</param>
/// <returns></returns>
[SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")]
[SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes",
Justification = "Never throw the exception in this case")]
public static bool TryParseEnum<T>(this string value, out T enumInstance)
{
try
{
enumInstance = Parse<T>(value, true);
return true;
}
catch
{
enumInstance = default(T);
return false;
}
}


/// <summary>
///
Gets the <see cref="DescriptionAttribute" /> of an <see cref="Enum" />
///
type value.
/// </summary>
/// <param name="value">
The <see cref="Enum" /> type value.</param>
/// <returns>
A string containing the text of the
/// <see cref="DescriptionAttribute"/>.</returns>
public static string GetDescription(this Enum value)
{
if (value == null)
throw new ArgumentNullException("value", CoreResources.NullValue);

string description = value.ToString();
FieldInfo fieldInfo = value.GetType().GetField(description);
EnumDescriptionAttribute[] attributes =
(EnumDescriptionAttribute[])
fieldInfo.GetCustomAttributes(typeof(EnumDescriptionAttribute), false);

if (attributes != null && attributes.Length > 0)
{
description = attributes[0].Description;
}
return description;
}

/// <summary>
///
Converts the <see cref="Enum" /> type to an <see cref="IList" />
///
compatible object.
/// </summary>
/// <param name="type">
The <see cref="Enum"/> type.</param>
/// <returns>
An <see cref="IList"/> containing the enumerated
/// type value and description.</returns>
public static IList ToList(this Type type)
{
if (type == null)
throw new ArgumentNullException("type", CoreResources.InvalidType);

ArrayList list = new ArrayList();
Array enumValues = Enum.GetValues(type);

foreach (Enum value in enumValues)
{
list.Add(new KeyValuePair<Enum, string>(value, GetDescription(value)));
}

return list;
}
}