August 16, 2008

Regular Expressions

For matching purposes:
? = 0 or 1 match
* = 0..n matches
+ = 1..n matches
{m,n} = from 'm' to 'n' matches where 'm' and 'n' are digits
{n} = exactly 'n' matches where 'n' is a digit
\d = numeric digit
\D = anything but a numeric digit
\s = any whitespace character
\S = any non-whitespace character
\w = Any alphabetical character and '_'
\W = Any non-alphabetical character or '_'

This example matches a United Kingdom postcode:
using System.Text.RegularExpressions;
...
const string PostCodeRegEx = @"(GIR0AA|[A-PR-UWYZ]([0-9]{1,2}|" + 
  "([A-HK-Y][0-9]|[A-HK-Y][0-9]([0-9]|[ABEHMNPRV-Y]))|" +
  "[0-9][A-HJKS-UW])[0-9][ABD-HJLNP-UW-Z]{2})";
public bool IsPostCode(string postCode)
{
    postCode = postCode.Trim().Replace(" ", string.Empty);
    bool res = Regex.IsMatch(postCode, PostCodeRegEx);
    return res;
}
This example Matches a SID:
using System.Text.RegularExpressions;
...
result = string.Empty;
const string SID_PATTERN = @"(\w-\d-\d-\d{2}-\d+-\d+-\d+)";
Regex reg = new Regex(SID_PATTERN);
MatchCollection mc = reg.Matches(sid);
if (mc.Count > 0)
{
    result = mc[0].Value;
}

Enums

See this blog entry for information and example on the use of DescriptionAttribute with Enums

This example uses an ComboBox to store the enumeration values as strings Preparing the Combobox
foreach (XXXEnum entry in Enum.GetValues(typeof(XXXEnum)))
    comboBox.Items.Add(entry);
OR
cbLoggingLevel.Items.AddRange(Enum.GetValues(typeof(XXXEnum)));

// Making an initial selection
comboBox.SelectedIndex = comboBox.Items.Count - 1; // Select the last one
OR
comboBox.SelectedIndex = 0; // Select the first
Converting to and from a string
//To convert an enum to a string use:
MyComboBox.SelectedItem = m_Object.XXXEnum .ToString();

//The reverse process is a little more complicated
XXXEnum gc = (XXXEnum ) Enum.Parse(typeof(XXXEnum ),
                        MyComboBox.SelectedItem.ToString(), true);
There is a better way to parse the enum from a string that I found here.:
public static class StringExtender
{
  public static TEnum ParseToEnum<TEnum>(this string name)
    where TEnum : struct
  {
    if (false == typeof(TEnum).IsEnum)
      throw new NotSupportedException(typeof(TEnum).Name + " must be an Enum");

    string trimmed = name.Trim();
    
    if (false == Enum.IsDefined(typeof(TEnum), trimmed))
      throw new ArgumentException(string.Format(
         "\'{0}\' is not defined in type of enum {1}", trimmed, typeof(TEnum).Name));

    return (TEnum)Enum.Parse(typeof(TEnum), trimmed);
  }
}
alternatively use the TryParse method.
public class EnumTester
{
  public enum DescriptionsEnum
  {
    None,
    AddOn,
    SnapOn,
    Adjacent,
    Fixed,
  };

  public void ParseEnumFromStringTest()
  {
    DescriptionsEnum test = DescriptionsEnum.None;
    test = StringExtender.ParseToEnum<DescriptionsEnum>("Adjacent");
    Debug.Assert(test == DescriptionsEnum.Adjacent);
    test = "Fixed".ParseToEnum<DescriptionsEnum>();
    Debug.Assert(test == DescriptionsEnum.Fixed);
    test = "   SnapOn  ".ParseToEnum<DescriptionsEnum>();
    Debug.Assert(test == DescriptionsEnum.SnapOn);
    //test = "      snapon    ".ParseToEnum<DescriptionsEnum>(); // FAILS!
    //Debug.Assert(test == DescriptionsEnum.SnapOn);

    bool success = Enum.TryParse<DescriptionsEnum>("Adjacent", out test);
    Debug.Assert(test == DescriptionsEnum.Adjacent);
    success = Enum.TryParse<DescriptionsEnum>("fixed", true, out test);
    Debug.Assert(test == DescriptionsEnum.Fixed);
    success = Enum.TryParse<DescriptionsEnum>("  fixed     ", true, out test);
    // Line below succeeds. - TryParse is more robust so use it instead!
    Debug.Assert(test == DescriptionsEnum.Fixed); 
  }
}

Iterating through enumerated types:
foreach (XXXEnum entry in Enum.GetValues(typeof(XXXEnum)))
{
    Debug.WriteLine(entry.ToString() + "=" + ((int)entry).ToString());                
}
See Flags Based Enumerated Types

Color

To create a color with a given RGB value use
Color color = Color.FromRGB(0xf1, 0xee, 0x45);
//otherwise
Color.Red, ...

Random Number Generator

Random class in .Net is part of System namespace
//Declare an object
Random randomNumberGenerator = new Random();
random.NextDouble() //to get the next random number between 0.0 and 1.0;
random.Next() // to get the next random positive integer number
// to get the next random integer, x where  'upper' <= x  < 'lower'
random.Next(lower, upper) 
Byte[] b = new Byte[10];
random.NextBytes(b); to set an array of bytes

//To set a seed for the random number generator
int seed = 137;
System.Random randomNumberGenerator = new System.Random(seed);

August 10, 2008

Ownerdraw ListView

Msdn: On Msdn Find this article with Google TODO: Add our code here

Standard Delegates And Events

Standard event handler, no delegate definition necessary.
public event EventHandler xxxChanged;
Standard delegate handler, no delegate definition necessary.
using System;
//public delegate void Action()
Action xxxDelegate = new Action(xxxMethod);

public delegate TResult Func()
//Use it with anonymous methods:
Func methodCall = delegate() { return xxx.MethodReturningABool(); };
//There are other Func overloads, eg:
//public delegate TResult Func()
Func convert = delegate(int s)
         { return i.ToString() }; 

OR
// definition: public delegate void MethodInvoker()
using  System.Windows.Forms;
...
MethodInvoker xxxDelegate = new MethodInvoker(xxxMethod);

Loading Objects Using Reflection

This helper class loads a bunch of objects from assemblies found in the specified search path. The objects must support an interface of the given type eg usage. List<ISomeInterface> plugIns = PluginHelper.LoadPlugins <ISomeInterface>(@".\");
class PluginHelper
{

  // Loading a bunch of objects dynamically using reflection
  // In this case the type parameter specifies an interface for
  // an object with a public default constructor
  public static IList<INTERFACE> LoadPlugins<INTERFACE>(
         string searchPath)
  //where INTERFACE :  // (only reference types)
  {
    List<INTERFACE> objList = new List<INTERFACE>();

    string[] files = Directory.GetFiles(searchPath, "*.dll");
    foreach (string file in files)
    {
      try
      {
        Assembly assembly = Assembly.LoadFrom(file);
        foreach (Type type in assembly.GetTypes())
        {
          if (!type.IsClass || type.IsNotPublic) continue;
          Type[] interfaces = type.GetInterfaces();
          if (((IList<Type>)interfaces).Contains(typeof(INTERFACE)))
          {
            try
            {

              // Find the default constructor
              ConstructorInfo conInfo = type.GetConstructor(new Type[0]);
              bool hasPublicDefaultConstructor = ((conInfo != null) &&
                  ((conInfo.Attributes | MethodAttributes.Public) > 0));
              if (hasPublicDefaultConstructor)
              {
                object obj = Activator.CreateInstance(type);
                INTERFACE instance = (INTERFACE)obj;
                Debug.Assert(instance != null);
                objList.Add(instance);
              }
              else
              {
                Trace.WriteLine("LoadPlugins<INTERFACE>() - Can not create the type \'" +
                    type.ToString() + "\' in assembly \'" + file +
                    "\' as it does not have a public default constructor");
              }
            }
            catch (Exception ex)
            {
              Trace.WriteLine("Exception occurred creating an instance of \'" +
                  type.ToString() + "\' from assembly \'" + file + "\'");
            }

          }

        }
      }
      catch (Exception ex)
      {
        Trace.WriteLine("Exception occurred trying to load from assembly \'" +
            file + "\'");
      }
    }
    return objList;
  }

}