Thursday, March 31, 2016

Opensourced the Numenta HTM.NET port

Hi readers,

As of now I've put a port of the HTM (Hierarchical Temporal Memory) network of numenta (NuPIC) on GitHub as an unofficial (working) port.


There is an official port of HTM in java, called HTM.Java which I've ported to .NET.
This version is a more biological interpretation of the original HTM network in python.

The goal is to stay as close as possible to this port and the biological approach as possible and maintain the same API.


  • Things that will be added in the future:
  • Vision integration (ImageSensor etc)
  • SDR (Sparse Dense Representation) Classifier integration (almost done at the point of writing)
  • Speed optimisations
  • KNN Classifier integration


I already have another post regarding this subject: Hierarchical Temporal Memory

The GitHub repository is: https://github.com/Zuntara/HTM.Net

Feel free to contribute ;)

Wednesday, February 24, 2010

Keeping focus on AJAX elements in an update panel

In a recent project a had to create an updatepanel in ASP.NET.
The creation of the panel was not the problem, the panel had a couple of textboxes and when the user 'tabs' between them, then a server-call was done to validate the input through a service.

It was an address-validation control. User inputs his address and it is checked on the fly against a service.

The problem was that when the user tabs, and the AJAX callback came back, then the focus of the next selected element was lost, resulting in irritating behavior that the user had to click with his mouse to the next field.

After a lot of searching I came up with a solution.

"Record which element has focus and put the focus back after the AJAX library destroyed the panel and rebuilds all the controls."
Let's jump into code:
- First I had to register a little script in the OnInit function of the ASP.NET Page:

protected override void OnInit(EventArgs e)
{
base.OnInit(e);

string scriptToRegister = "function SaveFocus(fieldId) { lastField"
+ UpdatePanel1.ClientID + " = fieldId; }
";

ScriptManager.RegisterClientScriptBlock(this, typeof(UserControl), "SaveScriptAddress", scriptToRegister, true);
....
}

Then I had to add this script as an attribute to all the textboxes in the updatepanel, that needed the focus. Those elements get updated when the ajax call returns.


protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
// onfocus=""
txtBoxNumber.Attributes.Add("onfocus", "SaveFocusAdv('" + txtBoxNumber.ClientID + "')");
txtHouseNumber.Attributes.Add("onfocus", "SaveFocusAdv('" + txtHouseNumber.ClientID + "')");
txtZipcode.Attributes.Add("onfocus", "SaveFocusAdv('" + txtZipcode.ClientID + "')");
txtddlStreets.Attributes.Add("onfocus", "SaveFocusAdv('" + txtddlStreets.ClientID + "')");
txtddlCities.Attributes.Add("onfocus", "SaveFocusAdv('" + txtddlCities.ClientID + "')");
txtddlStreets.Focus();
}
....
}


The C# coding is done at this point. All I had to do next was inserting a little javascript snippet in the ASP.NET Usercontrol markup:
This script was placed outside of the updatepanel! Because it may not be destroyed when the partial rendering kicks in.
Put the following code between a script tag:

var lastField<%= UpdatePanel1.ClientID %>;
Sys.WebForms.PageRequestManager.getInstance().add_beginRequest(BeginRequestHandler<%= UpdatePanel1.ClientID %>);
Sys.WebForms.PageRequestManager.getInstance().add_endRequest(EndRequestHandler<%= UpdatePanel1.ClientID %>);

function BeginRequestHandler<%= UpdatePanel1.ClientID %>(sender, args) {
document.body.style.cursor = 'wait';
}
function EndRequestHandler<%= UpdatePanel1.ClientID %>(sender, args) {
document.body.style.cursor = 'default';
if(lastField<%= UpdatePanel1.ClientID %> != undefined)
{
setTimeout('DoFocusOnLastElement(lastField<%= UpdatePanel1.ClientID %>)', 1);
}
}
function DoFocusOnLastElement( fieldId )
{
var element = document.getElementById(fieldId);
if(element != null) element.focus();
}

That's it, now the 'tabbing' will occur normally, like nothing else happens....
When the service takes a little longer then expected, then the user input is replaced by the content that the service sends back (like a city name) but that's not really a probem.
I hope this can be usefull to someone ;)
Regards,
W.

Sunday, January 24, 2010

How to Track the RuleEngine rules in WF without starting a workflow runtime

Gents,

Recently I had a problem at hands, I wanted to run run the RuleEngine from Workflow Foundation outside WF.
It is possible and easy to run the RuleEngine outside of WF, but the possibility to track which rules were executed was skipped, as far as I found and saw in the API.

You can track executed rules when you run the workflow runtime itself and attach a TrackingService, but it came out to slow in the test we did.

The problem was that every time we called a WCF service method, the runtime was started for executing a couple of rules, sounds like overkill to me.
So I created a little ‘hack’ to execute the rules with tracking without actually starting the workflow.

Let’s jump into code :)

I created a RuleHelper<T> that executes my rules.
Below you can find the execute method of the helper class:

public void Execute(T objectToRunRulesOn, bool trackData)
{
if (trackData)
{
// Create dummy ActivityExecutionContext and see that trackData is intercepted.
// Initialize with own activity and insert IWorkflowCoreRuntime

Type activityExecutionContext = typeof(Activity).Assembly.GetType("System.Workflow.ComponentModel.ActivityExecutionContext");
var ctor = activityExecutionContext.GetConstructor(BindingFlags.Instance BindingFlags.NonPublic, null,
new[] { typeof(Activity) }, null);
var activity = new InterceptingActivity();
var context = ctor.Invoke(new object[] { activity });

_ruleEngine = new RuleEngine(_ruleSet, typeof(T));
lock (SyncRoot)
{
InterceptingActivity.Track += InterceptingActivity_Track;
_ruleEngine.Execute(objectToRunRulesOn, (ActivityExecutionContext) context);
InterceptingActivity.Track -= InterceptingActivity_Track;
}
}
else
{
Execute(objectToRunRulesOn);
}
}


The intercepting activity does actually all the work.

We first create our own (dummy) ActiviyExecutionContext, problem was, that it is an ‘internal’ class.

The argument to the context is our own InterceptingActivity.
After the instantiation we create our RuleEngine (from the WF assemblies) with a loaded or created RuleSet and the type where to run the RuleSet on.
Then some plumbing code for multiple threads (SyncRoot) and then we attach a static event to the activity.
Next we will execute the rules with the RuleEngine on the specified object that needs checking, and with the self created context which has knowledge of our own created Activity.

Let’s see what the InterceptingActivity does:

using System;
using System.Reflection;
using System.Reflection.Emit;
using System.Workflow.Activities.Rules;
using System.Workflow.ComponentModel;
using System.Workflow.ComponentModel.Compiler;
using System.Workflow.Runtime;

namespace Whizzo.Framework.Rules
{
public class InterceptingActivity : Activity
{
// Some caching variables (ExecutionEvent)
private static FieldInfo _argsFieldInfo;
// Some caching variables (InjectAllTheNeededHandlers)
private static ConstructorInfo _executorCtr;
private static PropertyInfo _currActivity;
private static Delegate _handlerDelegate;
private static FieldInfo _workflowExecutionEventFieldInfo;
private static FieldInfo _workflowCoreRuntimeFieldInfo;

// Static event for tracking rules
public static event EventHandler<TrackingEventArgs> Track;

public InterceptingActivity()
: base("InterceptingActivity")
{
InjectAllTheNeededHandlers();
}

private void InjectAllTheNeededHandlers()
{
if (_handlerDelegate == null)
{
// Get the type of the WorkflowExecutor
Type executorType =
typeof (WorkflowEventArgs).Assembly.GetType("System.Workflow.Runtime.WorkflowExecutor");
// Get eventargs type, the event and the handler type
Type eventTypeType =
typeof (WorkflowEventArgs).Assembly.GetType(
"System.Workflow.Runtime.WorkflowExecutor+WorkflowExecutionEventArgs");
EventInfo evt = executorType.GetEvent("WorkflowExecutionEvent",
BindingFlags.Instance BindingFlags.NonPublic);
Type handlerType = TypeProvider.GetEventHandlerType(evt);
// Get current activity of WorkflowExecutor
_currActivity = executorType.GetProperty("CurrentActivity",
BindingFlags.Instance BindingFlags.NonPublic);
// Get the constructor
_executorCtr = executorType.GetConstructor(BindingFlags.Instance BindingFlags.NonPublic, null,
new[] {typeof (Guid)}, null);

// Get field which has the event handler
_workflowExecutionEventFieldInfo = executorType.GetField("_workflowExecutionEvent",
BindingFlags.Instance BindingFlags.NonPublic);
// Get workflowCoreRuntime field of activity
_workflowCoreRuntimeFieldInfo = typeof (Activity).GetField("workflowCoreRuntime",
BindingFlags.Instance BindingFlags.NonPublic);

// Create dynamic method in module of workflow
Module m = typeof (WorkflowEventArgs).Assembly.GetModules()[0];
DynamicMethod dm = new DynamicMethod("MyHandler", null, new[] {typeof (object), eventTypeType}, m, true);
MethodInfo execMethod = GetType().GetMethod("ExecutionEvent");

// Generate method body
ILGenerator ilgen = dm.GetILGenerator();
ilgen.Emit(OpCodes.Nop);
ilgen.Emit(OpCodes.Ldarg_0);
ilgen.Emit(OpCodes.Ldarg_1);
ilgen.Emit(OpCodes.Call, execMethod);
ilgen.Emit(OpCodes.Nop);
ilgen.Emit(OpCodes.Ret);

// Create delegate
_handlerDelegate = dm.CreateDelegate(handlerType);
}

// Create instance of WorkflowExecutor
object executor = _executorCtr.Invoke(new object[] { Guid.NewGuid() });
// Set current activity of WorkflowExecutor
_currActivity.SetValue(executor, this, null);

// Attach delegate to event
_workflowExecutionEventFieldInfo.SetValue(executor, _handlerDelegate);

// Set executor as workflowCoreRuntime
_workflowCoreRuntimeFieldInfo.SetValue(this, executor);
}

public static void ExecutionEvent(object sender, EventArgs eventArgs)
{
if(Track != null)
{
if (_argsFieldInfo == null)
{
_argsFieldInfo = eventArgs.GetType().GetField("_args",
BindingFlags.NonPublic BindingFlags.Instance);
}
var argsValue = _argsFieldInfo.GetValue(eventArgs);
// Extract args
RuleActionTrackingEvent args = (RuleActionTrackingEvent) argsValue;
Track(sender, new TrackingEventArgs(args));
}
}
}
}

InjectAllTheNeededHandlers is the most important method,
it will create a System.Workflow.Runtime.WorkflowExecutor and it will initialize all it’s needed variables to be able to execute the rules.

It will also attach a self created DynamicMethod converted to a Delegate as an event handler in the WorkflowExecutor.

The event will be fired by the executor (internal class of Microsoft) and this way we can intercept the result of the executed rules.

The method that will get fired is ExecutionEvent, which will fire another event if attached (in the Execute method of the helper) and which will pass the RuleName and the Result of execution.

Voila, hopefully this was a little bit clear :)

There are probably other ways to do this (without starting the runtime) but this way was good enough for me :)

At a blog (http://blogs.msdn.com/moustafa/archive/2006/08/05/689776.aspx) I also found another method to track the executed rules outside the workflow,
But it involved Tracing while this method uses the tracking inside the workflow, without actually executing it. It's a lot simpler, and probably cleaner.

You will have to enable tracing for WF and write a custom TraceListener.

But I prefer to do it without diagnostics tracing put on.

Some feedback in the comments indicated that there were a couple of thing short in the code I displayed above. I'll try to complete it a little more.

This is the TrackingEventArgs class, used for triggering the 'Track' event, which we subscribe to, to track the rules.



using System;
using System.Workflow.Activities.Rules;

namespace Whizzo.Framework.Rules
{
public class TrackingEventArgs : EventArgs
{

public TrackingEventArgs(RuleActionTrackingEvent args, string rulesetName)
{
Args = args;
RulesetName = rulesetName;
}

public RuleActionTrackingEvent Args { get; private set; }

public string RulesetName { get; private set; }

}
}

This is the complete RuleHelper class, I will show below how to call it:


using System;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Workflow.Activities.Rules;
using System.Workflow.Activities.Rules.Design;
using System.Workflow.ComponentModel;
using System.Reflection;
using System.Collections.Generic;

namespace Whizzo.Framework.Rules
{
public class RuleHelper<T>
{
private RuleSet _ruleSet;
private RuleEngine _ruleEngine;
private static readonly object SyncRoot = new object();
private List<TrackingEventArgs> _ruleMessages;

public RuleHelper()
{
_ruleMessages = new List<TrackingEventArgs>();
}

public void SetRules(RuleSet ruleSet)
{
_ruleSet = ruleSet;
}

public void Execute(T objectToRunRulesOn)
{
_ruleEngine = new RuleEngine(_ruleSet, typeof(T));
_ruleEngine.Execute(objectToRunRulesOn);
}

public void Execute(T objectToRunRulesOn, bool trackData)
{
if (trackData)
{
// Create dummy ActivityExecutionContext and see that trackData is intercepted.
// Initialize with own activity and insert IWorkflowCoreRuntime

Type activityExecutionContext = typeof(Activity).Assembly.GetType("System.Workflow.ComponentModel.ActivityExecutionContext");
var ctor = activityExecutionContext.GetConstructor(BindingFlags.Instance BindingFlags.NonPublic, null,
new[] { typeof(Activity) }, null);
var activity = new InterceptingActivity();
var context = ctor.Invoke(new object[] { activity });

_ruleEngine = new RuleEngine(_ruleSet, typeof(T));
lock (SyncRoot)
{
InterceptingActivity.Track += InterceptingActivity_Track;
_ruleEngine.Execute(objectToRunRulesOn, (ActivityExecutionContext)context);
InterceptingActivity.Track -= InterceptingActivity_Track;
}
}
else
{
Execute(objectToRunRulesOn);
}
}

public List<TrackingEventArgs> GetRuleMessages()
{
return _ruleMessages;
}

private void InterceptingActivity_Track(object sender, TrackingEventArgs e)
{
#if DEBUG
Console.WriteLine("{0} Rule result of {1} = {2}", e.RulesetName, e.Args.RuleName, e.Args.ConditionResult);
#endif
_ruleMessages.Add(e);
}
}
}

To use the RuleHelper<>, do something like this, it's pretty self-explainatory:

// Call the rules helper
RuleHelper ruleHelper = new RuleHelper();
// Set the rules
ruleHelper.SetRules(ruleSet);
// Execute the rules.
ruleHelper.Execute(rr, true);
// Get the tracked rules
var ruleMessages = ruleHelper.GetRuleMessages();

Regards,

W.

Friday, July 3, 2009

"Outlook could not create the work file. Check the TEMP environment variable"

This was the error I had when I had installed Office 2007
Word also had this error :

"Word could not create the work file. Check the TEMP environment variable"

After a while of searching and cursing, I've finally found the solution!

First I've took a look at the environment variables, but they pointed to the right directory -> %USERPROFILE%\Local Settings\Temp a lot of sites suggested that that was the problem, but the path was/is valid when I typed it in the explorer.

After a lot of configuration swimming I encountered that outlook also uses registry keys, more specificly these:

HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders

HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders


The 'cache' key of both registry entries.

When opening regedit, I saw that the 'User Shell Folders' key was pointing to a k: drive (which I didn't have): k:\Local\Microsoft\Windows\Temporary Internet Files

The 'Shell Folders' was pointing to C:\Users\Whizzo\AppData\Local\Microsoft\Windows\Temporary Internet Files

So I've changed the k drive to my user profile's temp folder:
%USERPROFILE%\Local Settings\Temp

And BAM, the problem was solved!!

I hope this is helpfull for someone ;)

Wednesday, September 3, 2008

Hierarchical Temporal Memory

It's been a while since I've posted a new topic, so I was thinking on what topic to post about on my blog. After a while of hard thinking and sleepless nights (just kidding) it stroked me... The idea entered my mind :)

I while ago I stumbled on an article somewhere regarding HTM (Hierarchical Temporal Memory)... 'What?' you may think? Well, it's an algorithm in A.I. invented by numenta if I'm not mistaken, and it's meant for classifying objects, or at least it can be used for it.

Imagine that you have a cat and a bowl of food in front of the cat, while the cat steps towards the bowl, the image of the bowl changes each step the cat takes.
The cat-brain must then determine whether the bowl is still the same bowl, it all happens in the sub-consciousness of the cat's brain, it's logical that it's the same bowl,
although the bowl is with every step different in size and perspective and if it’s a bummer the lighting may also be different.

Now if we want to translate it to image analysis with A.I., whether to know that an object is still in an image when we present a series of pictures (or movie) this methodology/technology becomes useful :)
It's an algorithm that functions in function of time.
You can pretty much compare it with an Self Organizing Map (SOM) network but in function of time, and with multiple layers.
Each layer is a specialization of the previous layer until the top layer has a classification answer with a certain belief that the thing in the picture is still the same thing.

The basic structure (from the algorithm document) is something like this:



I've found a particular document (paper) explaining the working of the algorithm and
for a more detailed and scientific explanation, I'll have to refer you to their amazing paper.
You can find it here.
As stubborn and curious I am, I'm trying to create something similar, but with my own twist of thought, actually I was thinking of such a mechanism for a long time before I’ve had found this algorithm, only the 'how to start on it' was still missing in my mind, this paper gave me a few ideas on how to create my own program/simulation.

I'll post my findings when my experiments with this algorithm are successful :)
Along with maybe if it's possible a basic peace of code for people who are interested in it for research or self-development.

I must mention that I've looked around on the web and didn't find a piece of code (except the numenta site) that implements this algorithm... such a bummer..
It has probably something to do with the patents obtained on this technology I guess.

Anyway, meanwhile receive my best regards and until the following post ;)

F.

Thursday, August 7, 2008

My first steps in embedded programming

Since I've always been interested in automatisation (domotics) and because I saw the introduction of a new module regarding embedded programming of GHI Electronics, I've bought a development board that makes it able to program through the .NET Micro Framework.

In the beginning I even had never heard of .NET Micro Framework, didn't know that it existed.

I got really excited because this board provides all kinds of interfaces you can think of, analog in/outputs, digital in/outputs, USB interfaces, Ethernet port, serial ports, parallel ports, etc..., even a little Piezo (=speaker) where you can buzz around with ;)

You can program managed in the micro framework, and when you deploy it, the framework uploads the code to the board, and then you can test it standalone.
It's great for making 'smart' devices, and since you can address the FAT file system on USB thumb drives/SD Cards, makes it possible that you can go really far in it.

The device also supports strong keyed assemblies, if you don't have a the right key, then the board will be flashed :) (Which is great :d, except when you've lost it...)

Here are some images of the device:

This is the development board, as you can see, all kinds of ports are present on it.



This is the master module, that contains the code (firmware).
It has also a lot of pins, where you can attach you own electronics on, if you know what you are doing :) The pins are located on the left and richt side of the PCB.
This module is located under the LCD display of the development board.



At the time of writing I've successfully succeeded at letting a LED blink on the board with a given frequency, and even fading of the LED worked ;)
I know, it's stupid but you have to start somewhere :)

Friday, June 27, 2008

Dirty check on objects

A problem that's pretty common is to determine whether an object has been changed, how do we know an object is changed?
You can use for example datasets; datasets keep track of changes, and can update only changed rows.

But in most of the projects that I had to work on, datasets weren't used, or as less as possible, they used their own domain model for storing and transmitting data from point a to point b.

Another problem they encountered was the fact that some of the objects marked as serializable are in fact not really serializable (they are, but have issues), like the ObservableCollection used in combination mostly with WPF. That class is marked serializable, but once you attach the added en removed events, then you can't serialize it anymore, because the delegates aren't marked NonSerializable.

Knowing that these were problems, I've created a solution to bypass all these problems without inheriting or wrapping or using surrogates or whatever.

I've used code that I've blogged about earlier in the IL section:
» Deep cloning objects with IL

This code has the ability to clone objects with IL, you can choose for cloning deeply or shallow, or to exclude fields from being cloned, you can also adapt it to work with other attributes for usage in WCF for example.
It can clone ObserveableCollection because it strips (ignores) the delegates from it.

The code I've written makes it possible to check for changes in an object, it doesn't really matter which object, because it uses a MD5 hash code. The only problem is: knowing what has been changed, but that's not needed in my case.
Feel free to contribute for knowing where the object has been changed, without wrapping it, or adding stuff to it :)

Here's the code that does all the work:

    /// <summary>
    /// Class for checking wether objects have been changed or not.
    /// Clones the object in order to check, for stripping events etc,
    /// but checks against the original object.
    /// Author:     Slaets Filip
    /// Date:       25/06/2008
    /// </summary>
    
public static class DirtyChecker
    {
        
/// <summary>
        /// Cache for holding hashed objects-data.
        /// </summary>
        
private static List<DirtyEntity> _hashesCache = new List<DirtyEntity>();

        
/// <summary>
        /// Retrieve a hashcode for an object.
        /// </summary>
        /// <param name="objToCheck">Object to get hashcode for.</param>
        /// <returns>hexadecimal hashcode</returns>
        
private static string GetHashRecord(object objToCheck)
        {
            
// Create our hash-record of this object.
            
MemoryStream ms = new MemoryStream();
            
BinaryFormatter bf = new BinaryFormatter();
            
bf.Serialize(ms, objToCheck);
            
MD5 md5 MD5.Create();
            
ms.Position 0;
            byte
[] hash md5.ComputeHash(ms);
            
// Convert the hashvalue to a HEX string.
            
StringBuilder sb = new StringBuilder();
            foreach 
(byte outputByte in hash)
            {
                
// Convert each byte to a Hexadecimal lower case string
                
sb.Append(outputByte.ToString("X2").ToLower());
            
}
            
return sb.ToString();
        
}

        
/// <summary>
        /// Check wether an object has changed somewhere or not.
        /// </summary>
        /// <param name="objToCheck">Object to check dirtyness of.</param>
        /// <returns>True when something has been changed in the object.</returns>
        
public static bool IsDirty(object objToCheck)
        {
            
if (objToCheck.GetType().GetCustomAttributes(typeof(SerializableAttribute), true).Length == 0)
            {
                
throw new ArgumentException("Object is not serializable, mark it with [Serializable]""objToCheck");
            
}

            
string name = string.Format("{0}.CloneHelper`1[[{1}]]"typeof(DirtyChecker).Namespace, objToCheck.GetType().AssemblyQualifiedName);
            
// Let's invoke the cloning mechanism
            
Type cloneType Type.GetType(name);
            if 
(cloneType == null)
                
throw new InvalidOperationException("Check the CloneHelper location, must be in same assembly and namespace as DirtyChecker!");
            
MethodInfo mi cloneType.GetMethod("Clone"new Type[] { objToCheck.GetType(), typeof(CloneType) });
            object 
toHashObject mi.Invoke(nullnew object[] { objToCheck, CloneType.ShallowCloning });

            string 
hashRecord GetHashRecord(toHashObject);
            
DirtyEntity entity = new DirtyEntity(objToCheck.GetHashCode(), hashRecord);
            if 
(!_hashesCache.Contains(entity))
            {
                _hashesCache.Add(entity)
;
                return false;
            
}

            DirtyEntity foundEntity 
_hashesCache[_hashesCache.IndexOf(entity)];
            if 
(foundEntity.HashRecord.Equals(entity.HashRecord, StringComparison.InvariantCulture))
            {
                
return false;
            
}
            
if (foundEntity.UpdateCascading)
            {
                foundEntity.HashRecord 
hashRecord;
            
}
            
return true;
        
}

        
/// <summary>
        /// Check wether an object has changed somewhere or not.
        /// </summary>
        /// <param name="objToCheck">Object to check dirtyness of.</param>
        /// <param name="cascaded">If the record is dirty, take the new record as base-record for checking dirtyness.</param>
        /// <returns>True when something has been changed in the object.</returns>
        
public static bool IsDirty(object objToCheck, bool cascaded)
        {
            
if (objToCheck.GetType().GetCustomAttributes(typeof(SerializableAttribute), true).Length == 0)
            {
                
throw new ArgumentException("Object is not serializable, mark it with [Serializable]""objToCheck");
            
}

            
string name = string.Format("{0}.CloneHelper`1[[{1}]]"typeof(DirtyChecker).Namespace, objToCheck.GetType().AssemblyQualifiedName);
            
// Let's invoke the cloning mechanism
            
Type cloneType Type.GetType(name)
            
MethodInfo mi cloneType.GetMethod("Clone"new Type[] { objToCheck.GetType() });
            object 
toHashObject mi.Invoke(nullnew object[] { objToCheck });

            string 
hashRecord GetHashRecord(toHashObject);
            
DirtyEntity entity = new DirtyEntity(objToCheck.GetHashCode(), hashRecord, cascaded);
            if 
(!_hashesCache.Contains(entity))
            {
                _hashesCache.Add(entity)
;
                return false;
            
}

            DirtyEntity foundEntity 
_hashesCache[_hashesCache.IndexOf(entity)];
            if 
(foundEntity.HashRecord.Equals(entity.HashRecord, StringComparison.InvariantCulture))
            {
                
return false;
            
}
            
if (foundEntity.UpdateCascading || cascaded)
            {
                foundEntity.HashRecord 
hashRecord;
            
}
            
return true;
        
}

        
/// <summary>
        /// Class for storing hashing data in the cache.
        /// </summary>
        
private class DirtyEntity
        {
            
private int _hashCodeOfObject;
            private string 
_hashRecord;
            private bool 
_updateCascading;

            public 
DirtyEntity(int hc, string hr)
            {
                _hashCodeOfObject 
hc;
                
_hashRecord hr;
                
_updateCascading = true;
            
}

            
public DirtyEntity(int hc, string hr, bool cascading)
            {
                _hashCodeOfObject 
hc;
                
_hashRecord hr;
                
_updateCascading cascading;
            
}

            
public int HashCodeOfObject
            {
                
get return _hashCodeOfObject}
                
set { _hashCodeOfObject = value; }
            }

            
public string HashRecord
            {
                
get return _hashRecord}
                
set { _hashRecord = value; }
            }

            
public bool UpdateCascading
            {
                
get return _updateCascading}
                
set { _updateCascading = value; }
            }

            
public override int GetHashCode()
            {
                
return base.GetHashCode();
            
}

            
public override bool Equals(object obj)
            {
                
if (obj is DirtyEntity)
                {
                    DirtyEntity de 
obj as DirtyEntity;
                    return 
de._hashCodeOfObject == this._hashCodeOfObject;
                
}
                
return base.Equals(obj);
            
}
        }
    }


bool IsDirty(object objToCheck) and bool IsDirty(object objToCheck, bool cascaded) the first one checks that the object is dirty against a previous version of the object, the previous version being the version when the IsDirty method is called for the first time.

The second method has the cascaded parameter, when it's set to true, then the method will compare against the previous called IsDirty result, each time it's called, the internal hashing-cache will be updated.

An example of usage:

// Create a list of 100 persons...
List<Person> list CreatePersonsList(100);

// Initialize the dirty checker to know how the object looks like
bool dirty1 DirtyChecker.IsDirty(list);

// Change something
list[0].Addresses[0].City "Jut City";

// Check again to see that something has been changed.
bool dirty2 DirtyChecker.IsDirty(list);

// Output:
// dirty1 = false;
// dirty2 = true;


Voila, if it's useful, let me know please ;)

Cheers!