Auditor

/// <summary>
        /// Audits property change events into a rolling session, with the dispose resulting in an output using whatever defined process is required
        /// </summary>
        /// <typeparam name="T"></typeparam>
        public class AuditSession<T> : IDisposable where T : INotifyPropertyChanged, INotifyPropertyChanging
        {
            /// <summary>
            /// Constructor for the audit session
            /// </summary>
            /// <param name="item"></param>
            public AuditSession(T item, AuditLogActionDelegate AuditLogAction)
            {
                item.PropertyChanged += new PropertyChangedEventHandler(item_PropertyChanged);
                targetProperties = typeof(T).GetProperties().ToDictionary(p=>p.Name);
                AuditedItem = item;
                auditLogAction = AuditLogAction;
            }

            /// <summary>
            /// A delegate to allow saving the audited data in an appropriate way at the end of the audit session
            /// </summary>
            /// <param name="auditedItem"></param>
            /// <param name="auditActions"></param>
            public delegate void AuditLogActionDelegate(T auditedItem, string auditActions);

            private AuditLogActionDelegate auditLogAction;

            private Dictionary<string, PropertyInfo> targetProperties;

            private void item_PropertyChanged(object sender, PropertyChangedEventArgs e)
            {
                if (changes.Length > 0)
                    changes.Append(", ");

                changes.Append("[@" + e.PropertyName + "] Set to '" + (targetProperties[e.PropertyName].GetValue(AuditedItem, null) ?? (object)"null").ToString() + "'");
            }

            /// <summary>
            /// The item being audited
            /// </summary>
            public T AuditedItem { get; private set; }

            private StringBuilder changes = new StringBuilder();

            /// <summary>
            /// The audited changes
            /// </summary>
            public string AuditedChanges
            {
                get
                {
                    return changes.ToString();
                }
            }

            /// <summary>
            /// Dispose of this item by writing out our audit changes and setting the audited item to null (and unbinding)
            /// </summary>
            public void Dispose()
            {
                try
                {
                    if (auditLogAction != null)
                    {
                        auditLogAction(AuditedItem, AuditedChanges);
                    }
                }
                finally
                {
                    AuditedItem.PropertyChanged -= new PropertyChangedEventHandler(item_PropertyChanged);
                    AuditedItem = default(T);
                    auditLogAction = null;
                }
            }
        }