Click here to Skip to main content
15,891,513 members
Articles / Programming Languages / C#

Applied Use of LinFu/Cecil and Aspect-Oriented Programming Concepts - A Library

Rate me:
Please Sign up or sign in to vote.
4.88/5 (8 votes)
4 Sep 2008CPOL17 min read 35.2K   160   32  
A library of useful functionality using Aspect-Oriented Programming concepts, and implemented using the LinFu and Cecil.Mono projects/frameworks.
using System;
using System.Reflection;
using System.Windows.Forms;

using System.Collections.Generic;
using System.IO;
using System.ComponentModel;
using System.Collections;
using System.Text;
using System.Threading;
using System.Runtime.Serialization.Formatters.Binary;

using BrainTechLLC.ThreadSafeObjects;

namespace BrainTechLLC
{
	public static class MockObjectRepository
	{
		private static string _saveFilename;

		public static bool MockRecordingEnabled { get; set; }
		public static bool MockReplayEnabled { get; set; }

		internal static ThreadSafeLookup<Type, MockObjectsForClass> MockObjectsByClass = new ThreadSafeLookup<Type, MockObjectsForClass>();

		public static int MockCount
		{
			get
			{
				int count = 0;
				List<MockObjectsForClass> list1 = MockObjectsByClass.AllItems;
				for (int n = 0; n < list1.Count; n++)
				{
					MockObjectsForClass mockClass = list1[n];
					List<MockObjectsForMethod> mockMethods = mockClass.LookupByMethodName.AllItems;
					for (int a = 0; a < mockMethods.Count; a++)
					{
						MockObjectsForMethod mockMethod = mockMethods[a];
						count += mockMethod.LookupByParameters.AllTerminatingItemsList.Count;
					}
				}
				return count;
			}
		}

		public static int AddMockObjectsFromFile(string pathAndFileName)
		{
			int count = 0;

			if (File.Exists(pathAndFileName))
			{
				byte[] bytes = File.ReadAllBytes(pathAndFileName);
				ThreadSafeLookup<Type, MockObjectsForClass> loaded = bytes.DeserializeFromCompressedBinary() as ThreadSafeLookup<Type, MockObjectsForClass>;

				List<MockObjectsForClass> allMockClasses = loaded.AllItems;
				for (int n = 0; n < allMockClasses.Count; n++)
				{
					MockObjectsForClass mockClass = allMockClasses[n];
					List<MockObjectsForMethod> mockMethods = mockClass.LookupByMethodName.AllItems;
					for (int a = 0; a < mockMethods.Count; a++)
					{
						MockObjectsForMethod mockMethod = mockMethods[a];
						List<KeyValuePair<List<int>, StoredParametersAndReturnValue>> allStored = mockMethod.LookupByParameters.AllTerminatingItemsList;
						foreach (KeyValuePair<List<int>, StoredParametersAndReturnValue> kvpStored in allStored)
						{
							StoredParametersAndReturnValue stored = kvpStored.Value;
							stored.UnpackageMockFromStorage(true, true);
							mockClass.ClassType.RecordMockObjectReturnValue(mockMethod.MethodName, stored.Parameters.ToArray(), stored.ReturnValue);
							count++;
						}
					}
				}
			}

			return count;
		}

		public static int SaveMockObjectsToFile(string pathAndFileName)
		{
			byte[] bytes = MockObjectsByClass.SerializeToCompressedBinary();
			File.WriteAllBytes(pathAndFileName, bytes);
			return MockCount;
		}

		public static void EnableMockRecording(this Type t, bool enabled)
		{
			if (enabled)
				MockRecordingEnabled = true;

			MockObjectsForClass mocks = RetrieveMockObjectsForClass(t);
			mocks.MockRecordingEnabled = enabled;
		}

		public static MockObjectsForClass RetrieveMockObjectsForClass(this Type t)
		{
			MockObjectsForClass result = MockObjectsByClass[t];

			if (result == null)
			{
				result = new MockObjectsForClass() { ClassType = t, MockRecordingEnabled = true };
				MockObjectsByClass.AddOrSet(t, result);
			}

			return result;
		}

		public static StoredParametersAndReturnValue GetMockObject(this Type t, string methodName, params object[] parameters)
		{
			// Retrieve the structure that holds all recorded objects for class type t
			MockObjectsForClass mockObjects = RetrieveMockObjectsForClass(t);

			// Calculate a list of hash values that can be used to uniquely identify parameter values
			List<int> paramHash = GetParametersHash(parameters);

			// Retrieve the structure that holds all recorded objects for a specific method name
			MockObjectsForMethod methodMocks = mockObjects.GetMockObjectsForMethod(methodName);

			// Find a pre-recorded return value for this class type, method name, and parameter values
			StoredParametersAndReturnValue found = methodMocks.LookupByParameters.FindItem(paramHash.ToArray());

			// The return value may need to be unpacked from compressed binary storage
			if (found != null && found.IsPacked)
				found.UnpackageMockFromStorage(true, true);

			return found;
		}

		public static StoredParametersAndReturnValue RecordMockObjectReturnValue(this Type t, string methodName, object[] parameters, object returnValue)
		{	
			// Retrieve the structure that holds all recorded objects for class type t
			MockObjectsForClass mockObjects = RetrieveMockObjectsForClass(t);

			// Calculate a list of hash values that can be used to uniquely identify parameter values
			List<int> paramHash = GetParametersHash(parameters);
			int[] paramsHashArray = paramHash.ToArray();

			// Retrieve the structure that holds all recorded objects for a specific method name
			MockObjectsForMethod methodMocks = mockObjects.GetMockObjectsForMethod(methodName);

			// Find any existing stored parameters/return value associated with this combo of 
			// type, method name, and parameters.
			StoredParametersAndReturnValue found = methodMocks.LookupByParameters.FindItem(paramsHashArray);
			
			if (found == null)
				found = new StoredParametersAndReturnValue();
			else
				methodMocks.LookupByParameters.RemoveTerminatingItem(paramsHashArray);

			// Set up values in StoredParametersAndReturnValue
			found.ListOfParameterHash = paramHash;
			found.Parameters = new List<object>(parameters);
			found.ReturnValue = returnValue;

			// Add this instance of StoredParametersAndReturnValue to the lookup data structure
			methodMocks.LookupByParameters.AddTerminatingItem(found, paramsHashArray);

			return found;
		}

		public static List<int> GetParametersHash(object[] parameters)
		{
			List<int> results = new List<int>();

			for (int n = 0; n < parameters.Length; n++)
			{
				int hash = GetHashForParameter(parameters[n]);
				results.Add(hash);
			}

			return results;
		}

		public static void EnableRecording(string saveFilename)
		{
			_saveFilename = saveFilename;

			MockRecordingEnabled = true;
			MockReplayEnabled = false;
		}

		public static void FinishRecording()
		{
			if (!string.IsNullOrEmpty(_saveFilename))
			{
				SaveMockObjectsToFile(_saveFilename);
			}
		}

		public static void EnablePlayback(string mockDataFileName)
		{
			if (!string.IsNullOrEmpty(mockDataFileName))
				AddMockObjectsFromFile(mockDataFileName);

			MockRecordingEnabled = false;
			MockReplayEnabled = true;
		}

		public static int GetHashForParameter(object o)
		{
			if (o == null)
				return -99;

			int hash = 0;

			if (o.ForEachIfArray<object>(delegate(object item) { hash += GetHashForParameter(item); }))
				return hash;

			return o.GetHashCode();
		}

		public static bool ForEachIfArray<T>(this object o, TDelegateGeneral<T> del) where T : class
		{
			return o.ForEachIfArray(o.GetType(), del);
		}

		public static bool ForEachIfArray<T>(this object o, Type t, TDelegateGeneral<T> del) where T : class
		{
			if (t.IsArray)
			{
				Array a = o as Array;
				foreach (object item in a)
				{
					del(item as T);
				}

				return true;
			}

			return false;
		}

		public static bool DoIfType<T>(this object o, Type t, TDelegateGeneral<T> del) where T : class
		{
			if (typeof(T).IsAssignableFrom(t))
			{
				del(o as T);
			}
			return false;
		}
	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) Troppus Software
United States United States
Currently working as a Senior Silverlight Developer with Troppus Software in Superior, CO. I enjoy statistics, programming, new technology, playing the cello, and reading codeproject articles. Smile | :)

Comments and Discussions