Tuesday, August 17, 2010

C# Delegates

Nice post on Action, Predicate, and Func delegates: Cool Delegates

Quick Reference:
/*
* Action -    
*    o accepts zero or up to four parameters and returns void
*    o Action                         :: public delegate void DelegateName()
*    o Action<T>                      :: public delegate void DelegateName(T)
*    o Action<T1, T2>                 :: public delegate void DelegateName(T1, T2)
*    o Action<T1, T2, T3>             :: public delegate void DelegateName(T1, T2, T3)
*    o Action<T1, T2, T3, T4>         :: public delegate void DelegateName(T1, T2, T3, T4)
* 
* Predicate - 
*    o accepts a single parameter and returns a bool  
*    o Predicate<T>                   :: public delegate bool DelegateName(T)
*     
* Func -
*    o acepts zero or up to four parameters and returns any type (TResult)
*    o Func<TResult>                  :: public delegate <TResult> DelegateName()
*    o Func<T, TResult>               :: public delegate <TResult> DelegateName(T1)
*    o Func<T1, T2, TResult>          :: public delegate <TResult> DelegateName(T1, T2)
*    o Func<T1, T2, T3, TResult>      :: public delegate <TResult> DelegateName(T1, T2, T3)
*    o Func<T1, T2, T3, T4, TResult>  :: public delegate <TResult> DelegateName(T1, T2, T3, T4)
* 
*/

System.Environment - EnvironmentList Utility Class

I'm traditionally a Web developer; however, lately I've found myself doing a bunch of console work to help automate various tasks (including work flow, file and report merging, moving builds to various environments, etc...).  I've come to embrace, among many, the System.IO.Path, System.Environment, and System.Diagnostics.Process classes.  These classes help manipulate file and directory paths, provide information about means of manipulating the current environment, and access to starting and stopping local services.

I often find myself investigating these class and their members and forgetting exactly what the member does.  I'll locate a property or method that sounds like and is described (via comments) as something I would like to use; however, the comments are short and sweet and I must have a dozen questions pop in my mind.  Note to self - create a framework for interactive library documentation .  I digress... I'll typically create a quick console app an determine if the respective member is what I really need.  This takes time - every time!  So, I came up with a utility class...

The following is a informational utility class that builds a collection of key: value pair of the current environment.  Fundamentally, all that this class does is abstract and enumerate the various members of the System.Environment class, puts the results into a list of key: value pairs, and provides a property that exposes the results.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq.Expressions;

/// <summary>
/// Environment List Class.
/// </summary>
public partial class EnvironmentList
{
   #region Fields
   #endregion Fields

   #region Properties
   /// <summary>
   /// Gets the Environment Key: Value collection.
   /// </summary>
   /// <value>The items.</value>
   public List<KeyValuePair<string, string>> Items { get; private set; }
   #endregion Properties

   #region Methods
   /// <summary>
   /// Builds the Environment dictionary/list.
   /// </summary>
   private void BuildDictionary()
   {
      this.Items.Add(new KeyValuePair<string, string>(ReflectionUtility.GetPropertyName(() => Environment.SystemDirectory), Environment.SystemDirectory));
      this.Items.Add(new KeyValuePair<string, string>(ReflectionUtility.GetPropertyName(() => Environment.CurrentDirectory), Environment.CurrentDirectory));
      this.Items.Add(new KeyValuePair<string, string>(ReflectionUtility.GetPropertyName(() => Environment.MachineName), Environment.MachineName));
      this.Items.Add(new KeyValuePair<string, string>(ReflectionUtility.GetPropertyName(() => Environment.OSVersion), Environment.OSVersion.ToString()));
      this.Items.Add(new KeyValuePair<string, string>(ReflectionUtility.GetPropertyName(() => Environment.Version), Environment.Version.ToString()));
      this.Items.Add(new KeyValuePair<string, string>(ReflectionUtility.GetPropertyName(() => Environment.UserName), Environment.UserName));
      this.Items.Add(new KeyValuePair<string, string>(ReflectionUtility.GetPropertyName(() => Environment.UserDomainName), Environment.UserDomainName));
      this.Items.Add(new KeyValuePair<string, string>(ReflectionUtility.GetPropertyName(() => Environment.ProcessorCount), Environment.ProcessorCount.ToString()));

      foreach (string name in Enum.GetNames(typeof(Environment.SpecialFolder)))
         this.Items.Add(new KeyValuePair<string, string>(name, Environment.GetFolderPath((Environment.SpecialFolder)Enum.Parse(typeof(Environment.SpecialFolder), name))));

      this.Items.Add(new KeyValuePair<string, string>("Logical Drives", string.Join("; ", Environment.GetLogicalDrives())));

      ParseEnvironmentVariables(EnvironmentVariableTarget.Machine);
      ParseEnvironmentVariables(EnvironmentVariableTarget.Process);
      ParseEnvironmentVariables(EnvironmentVariableTarget.User);
   }

   /// <summary>
   /// Parses the environment variables in the context of @target.
   /// </summary>
   /// <param name="target">The target.</param>
   private void ParseEnvironmentVariables(EnvironmentVariableTarget target)
   {
      foreach (DictionaryEntry item in Environment.GetEnvironmentVariables(target))
      {
         this.Items.Add(new KeyValuePair<string, string>(item.Key.ToString(), item.Value.ToString()));
      }
   }
   #endregion Methods

   #region Event Handlers
   #endregion Event Handlers

   #region Ctors
   /// <summary>
   /// Initializes a new instance of the <see cref="EnvironmentList"/> class.
   /// </summary>
   public EnvironmentList()
   {
      this.Items = new List<KeyValuePair<string, string>>();
      this.BuildDictionary();
   }
   #endregion Ctors
}

/// <summary>
/// Reflection Utility Class
/// <see cref="http://handcraftsman.wordpress.com/2008/11/11/how-to-get-c-property-names-without-magic-strings/"/>
/// </summary>
public static class ReflectionUtility
{
   /// <summary>
   /// Gets the name of the property.
   /// </summary>
   /// <typeparam name="T"></typeparam>
   /// <param name="expression">The expression.</param>
   /// <returns></returns>
   public static string GetPropertyName<T>(Expression<Func<T>> expression)
   {
      MemberExpression body = (MemberExpression)expression.Body;
      return body.Member.Name;
   }
}
To use the class, instantiate the EnvironmentList object and enumerate the Items property.

Console:
EnvironmentList el = new EnvironmentList();
Array.ForEach(el.Items.ToArray(), i => Console.Out.WriteLine("{0}: {1}{2}", i.Key, i.Value, Environment.NewLine));
Web:

Add a GridView to the markup and bind the grid on page load:
<asp:GridView runat="server" id="gv"/>
EnvironmentList el = new EnvironmentList();
this.gv.DataSource = el.Items;
this.gv.DataBind();
Nothing Earth shattering here, but a nice utility if you need to view the properties of the System.Environment class for the current environment.

Thanks for reading...