SCNA 2011

Posted by Eric November 21st, 2011

SCNA 2011 better known as “Holy Crap, do I have a ton more to think about concerning my craft!”

From the terrific conversations while driving from/to Cleveland with Michael “Doc” Norton, Joe Fiorini, Randy Eppinger, Melissa Lewis & Zee Spencer to the fantastic talks given by all speakers as well as the hallway conversations with folks I haven’t met before or I haven’t seen in a while, SCNA was a blast.

Many of the talks were thought provoking and I hope to write a little something about some of them as well as follow up on posts that I’m sure will appear from some of my LeanDog compatriots.

Threaded/Recursive Objects in Rails 3.0.x & Mongoid 2.0.x

Posted by Eric July 29th, 2011

So I am building a useful internal app for work in Rails 3 (soon to be 3.1), Ruby 1.9.2 & MongoDB. For those of you that know me, it’s a bit of stepping out of my comfort zone of experience with .NET. However, I’m really digging the power of the Ruby language and Rails environment so it’s all good.

So with that said, I’m learning how to do some things with MongoDB & Mongoid that I had run into some trouble with. I’m planning to do a few posts coming up that will be just knowledge dumps and would hopefully be useful to some folks that may be running into the same problems as I did.

One of the things I wanted to do was provide the ability to have threaded comments in the system. Due to the schemaless design of MongoDB, this should be relatively easy. Some of you may have seen this gist then you have encountered the older way to handle this kind of situation where a Comment object would be able to be embedded within a Comment object.

Let’s start with a plain Comment Mongoid document class in Ruby.

require 'mongoid'

class Comment
  include Mongoid::Document
  include Mongoid::Timestamps

  field :title, type: String
  field :body, type: String

  validates_presence_of :body

  attr_accessible :title, :body
end

Now, Mongoid 2.0.x now supports recursive models instead of using the syntax seen in the gist. This just requires one line to be added to the class:

recursively_embeds_many

Adding in this will now provide your Comment Mongoid model with two new methods: parent_comment & child_comments. These are dynamically created based on the name of your class (parent_# & child_#s) and they allow you to traverse the hierarchy.

The Comment model would now look something like:

require 'mongoid'

class Comment
  include Mongoid::Document
  include Mongoid::Timestamps

  field :title, type: String
  field :body, type: String

  #comment.parent_comment # => Gets the parent.
  #comment.child_comments # => Gets the children.
  recursively_embeds_many

  validates_presence_of :body

  attr_accessible :title, :body
end

That’s it! Not so bad once I read the upgrade page that this was changed.

Tags: , ,

Typed access to app.config & HTTP params

Posted by Eric March 30th, 2011

How many times have you pulled values from your app.config and needed to convert them to something other than a string? What about wanting to not only do that but also make your configuration related class testable? Well, I got tired of dealing with the app.config appSettings values with the constant data type conversion that had to be written each time I built an app.

Some time ago a good friend wrote a class, for a project we were working on together, that would allow you to get the values in the HTTP QueryString collection and return them typed as int, string, Enum, etc. It was really useful at the time so I decided to write a from scratch improved version of the class, Test Driven, using the functionality that I remembered to be my guide along with what I felt was lacking.

One of the things we didn’t do at the time was leverage the new System.Web.Abstractions assembly (that contains the HttpContextWrapper and HttpContextBase classes) to allow interaction with the HttpContext and allow me to Mock the context using Moq. We want to set all our interactions with the HttpContextBase, like so:

	private HttpContextBase _context;

	public HttpParameters()
	{
		_context = new HttpContextWrapper(HttpContext.Current);
	}

	public HttpParameters(HttpContextBase baseContext)
	{
		_context = baseContext;
	}

The “magic” happens with the built in TypeConverter in the .NET Framework, along with default(T) and some additional checking to deal with special ValueType cases such as Enum & boolean.

protected T GetValue<T>(T nullValue, string keyValue)
{
	T result = default(T);
	Type returnType = typeof(T);

	if (!string.IsNullOrEmpty(keyValue))
	{
		TypeConverter valueConverter = TypeDescriptor.GetConverter(returnType);

		if (valueConverter.CanConvertFrom(keyValue.GetType()))
		{
			if (returnType.IsEnum)
			{
				if (Enum.IsDefined(returnType, keyValue))
				{
					result = (T)valueConverter.ConvertFrom(null, null, keyValue);
				}
			}
			else if (returnType == typeof(bool))
			{
				if (IsNumeric(keyValue))
				{
					result = (T)valueConverter.ConvertFrom(null, null, Convert.ToBoolean(Convert.ToInt32(keyValue)).ToString());
				}
				else
				{
					if (keyValue.ToLower() == "false" || keyValue.ToLower() == "true")
					{
						result = (T)valueConverter.ConvertFrom(null, null, keyValue);
					}
				}
			}
			else
			{
				result = (T)valueConverter.ConvertFrom(null, null, keyValue);
			}
		}
	}
	else
	{
		result = nullValue;
	}

	return result;
}

protected bool IsNumeric(string text)
{
	Regex pattern = new Regex("[^0-9]");
	return !pattern.IsMatch(text);
}

The Typeconverter can also be leveraged to handle the app.config appSettings section. An example, with Interfaces for injection & unit testing, along with my unit tests is located in the elh.framework project on my GitHub account.

Eventually I’ll be adding in more classes & extension methods that I find useful and updating the GitHub project as time permits.

Tags: , , , ,

The Times They Are a-Changin’

Posted by Eric February 23rd, 2011

So it’s been a fairly crazy 4 years that I have been with The Firm That Shall Not Be Named(tm) as a Lead .NET Developer. I’ve been on a number of projects with a number of really great folks at the Cleveland, OH office.

I have grown a bit while at The Firm but my interests have grown and changed over the years. As the IT organization has reorganized a few times over my tenure, it became more apparent to me that I wanted more out of my career & to get more deeply involved in Agile practices & coaching while keeping my technical prowess up to snuff. I also have an interest in sharing my knowledge with others & collaborating in software development.

I’m proud to announce that I will be joining the LeanDog team as an Agile Coach & Developer. Depending on the need, I will be embedded in client development teams doing Agile coaching as well as being part of the overall effort for the client team to deliver quality testable software. I may also be involved in dev projects “On The Boat”.

I’m really pumped and looking forward to being a part of a great team of really talented folks all united in our commitment to delivering quality software and value to our customers.

Tags:

Memoization in .NET

Posted by Eric February 23rd, 2011

Wikipedia defines memoization as:

In computing, memoization is an optimization technique used primarily to speed up computer programs by having function calls avoid repeating the calculation of results for previously-processed inputs. Memoization has also been used in other contexts (and for purposes other than speed gains), such as in simple mutually-recursive descent parsing[1] in a general top-down parsing algorithm[2][3] that accommodates ambiguity and left recursion in polynomial time and space. Although related to caching, memoization refers to a specific case of this optimization, distinguishing it from forms of caching such as buffering or page replacement. In the context of some Logic Programming languages, memoization is also known as tabling.[4] – [more]

I’ve been meaning to write something in .NET to be able to do this. After doing some Googling and seeing what other people have come up with, it appeared to me that I didn’t need Lambda expressions or something fancy to do this, but I had to be able to make sure that I could use the functionality on any class. So, I ran onto an answer on StackOverflow: C# – Refactor and Remove Duplication From this Memoization Code. The implementation relies on Func<T> and its variants, which appeared in .NET 3.5, to make the “magic” happen.

What I have done is take the code in the StackOverflow question and modify it to create the cache key based on not only the class, but also the method. Also when the Reset method is called, we don’t necessarily want to completely blow away the entire cache. We really only want to remove any of the cache keys related specifically to the memoization.

Enough talk, code!

using System;
using System.Web.Caching;

namespace MemoizationTester
{
    public static class Memoize
    {
        // .NET 3.5 only supports up to 4 params to a Func<T>
        // .NET 4.0 supports up to 16 params to a Func<T>

        // 5 Params
        public delegate TResult Func<T1, T2, T3, T4, T5, TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5);

        // 6 Params
        public delegate TResult Func<T1, T2, T3, T4, T5, T6, TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6);

        // 7 Params
        public delegate TResult Func<T1, T2, T3, T4, T5, T6, T7, TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7);

        // 8 Params
        public delegate TResult Func<T1, T2, T3, T4, T5, T6, T7, T8, TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5, T6 arg6, T7 arg7, T8 arg8);

        public static Cache LocalCache = System.Web.HttpRuntime.Cache ?? System.Web.HttpContext.Current.Cache;

        /// <summary>
        /// Helps to provide a consistent string that can be searched for in Cache collection.
        /// </summary>
        private const string MemoizeCacheKey = "memoize_";

        /// <summary>
        /// Memoize a Method call that takes no Parameters.
        /// </summary>
        /// <typeparam name="TResult">The <see cref="System.Type"/> of the method result.</typeparam>
        /// <param name="func">The class method you want to memoize.</param>
        /// <param name="durationInSeconds">The duration in seconds that you want to cache the method call result.</param>
        /// <returns>The memoized method's result data.</returns>
        public static TResult ResultOf<TResult>(
            Func<TResult> func,
            long durationInSeconds)
        {
            var key = HashArguments(
                func.Method.DeclaringType.GUID,
                func.Method.Name
                );

            return Complete(key, durationInSeconds, func);
        }

        /// <summary>
        /// Memoize a Method call that takes 1 Parameter.
        /// </summary>
        /// <typeparam name="TArg1">The <see cref="System.Type"/> of the class method's first parameter.</typeparam>
        /// <typeparam name="TResult">The <see cref="System.Type"/> of the method result.</typeparam>
        /// <param name="func">The class method you want to memoize.</param>
        /// <param name="arg1">The value of the class method's first parameter.</param>
        /// <param name="durationInSeconds">The duration in seconds that you want to cache the method call result.</param>
        /// <returns>The memoized method's result data.</returns>
        public static TResult ResultOf<TArg1, TResult>(
            Func<TArg1, TResult> func,
            TArg1 arg1,
            long durationInSeconds)
        {
            var key = HashArguments(
                func.Method.DeclaringType.GUID,
                func.Method.Name,
                typeof(TArg1).GUID,
                (object)arg1);

            return Complete(key, durationInSeconds, () => func(arg1));
        }

        /// <summary>
        /// Memoize a Method call that takes 2 Parameters.
        /// </summary>
        /// <typeparam name="TArg1">The <see cref="System.Type"/> of the class method's first parameter.</typeparam>
        /// <typeparam name="TArg2">The <see cref="System.Type"/> of the class method's second parameter.</typeparam>
        /// <typeparam name="TResult">The <see cref="System.Type"/> of the method result.</typeparam>
        /// <param name="func">The class method you want to memoize.</param>
        /// <param name="arg1">The value of the class method's first parameter.</param>
        /// <param name="arg2">The value of the class method's second parameter.</param>
        /// <param name="durationInSeconds">The duration in seconds that you want to cache the method call result.</param>
        /// <returns>The memoized method's result data.</returns>
        public static TResult ResultOf<TArg1, TArg2, TResult>(
            Func<TArg1, TArg2, TResult> func,
            TArg1 arg1,
            TArg2 arg2,
            long durationInSeconds)
        {
            var key = HashArguments(
                func.Method.DeclaringType.GUID,
                func.Method.Name,
                typeof(TArg1).GUID,
                (object)arg1,
                typeof(TArg2).GUID,
                (object)arg2);

            return Complete(key, durationInSeconds, () => func(arg1, arg2));
        }

        /// <summary>
        /// Memoize a Method call that takes 3 Parameters.
        /// </summary>
        /// <typeparam name="TArg1">The <see cref="System.Type"/> of the class method's first parameter.</typeparam>
        /// <typeparam name="TArg2">The <see cref="System.Type"/> of the class method's second parameter.</typeparam>
        /// <typeparam name="TArg3">The <see cref="System.Type"/> of the class method's third parameter.</typeparam>
        /// <typeparam name="TResult">The <see cref="System.Type"/> of the method result.</typeparam>
        /// <param name="func">The class method you want to memoize.</param>
        /// <param name="arg1">The value of the class method's first parameter.</param>
        /// <param name="arg2">The value of the class method's second parameter.</param>
        /// <param name="arg3">The value of the class method's third parameter.</param>
        /// <param name="durationInSeconds">The duration in seconds that you want to cache the method call result.</param>
        /// <returns>The memoized method's result data.</returns>
        public static TResult ResultOf<TArg1, TArg2, TArg3, TResult>(
            Func<TArg1, TArg2, TArg3, TResult> func,
            TArg1 arg1,
            TArg2 arg2,
            TArg3 arg3,
            long durationInSeconds)
        {
            var key = HashArguments(
                func.Method.DeclaringType.GUID,
                func.Method.Name,
                typeof(TArg1).GUID,
                (object)arg1,
                typeof(TArg2).GUID,
                (object)arg2,
                typeof(TArg3).GUID,
                (object)arg3);

            return Complete(key, durationInSeconds, () => func(arg1, arg2, arg3));
        }

        /// <summary>
        /// Memoize a call that takes 4 Parameters.
        /// </summary>
        /// <typeparam name="TArg1">The <see cref="System.Type"/> of the class method's first parameter.</typeparam>
        /// <typeparam name="TArg2">The <see cref="System.Type"/> of the class method's second parameter.</typeparam>
        /// <typeparam name="TArg3">The <see cref="System.Type"/> of the class method's third parameter.</typeparam>
        /// <typeparam name="TArg4">The <see cref="System.Type"/> of the class method's fourth parameter.</typeparam>
        /// <typeparam name="TResult">The <see cref="System.Type"/> of the method result.</typeparam>
        /// <param name="func">The class method you want to memoize.</param>
        /// <param name="arg1">The value of the class method's first parameter.</param>
        /// <param name="arg2">The value of the class method's second parameter.</param>
        /// <param name="arg3">The value of the class method's third parameter.</param>
        /// <param name="arg4">The value of the class method's fourth parameter.</param>
        /// <param name="durationInSeconds">The duration in seconds that you want to cache the method call result.</param>
        /// <returns>The memoized method's result data.</returns>
        public static TResult ResultOf<TArg1, TArg2, TArg3, TArg4, TResult>(
            Func<TArg1, TArg2, TArg3, TArg4, TResult> func,
            TArg1 arg1,
            TArg2 arg2,
            TArg3 arg3,
            TArg4 arg4,
            long durationInSeconds)
        {
            var key = HashArguments(
                func.Method.DeclaringType.GUID,
                func.Method.Name,
                typeof(TArg1).GUID,
                (object)arg1,
                typeof(TArg2).GUID,
                (object)arg2,
                typeof(TArg3).GUID,
                (object)arg3,
                typeof(TArg4).GUID,
                (object)arg4);

            return Complete(key, durationInSeconds, () => func(arg1, arg2, arg3, arg4));
        }

        /// <summary>
        /// Memoize a call that takes 5 Parameters.
        /// </summary>
        /// <typeparam name="TArg1">The <see cref="System.Type"/> of the class method's first parameter.</typeparam>
        /// <typeparam name="TArg2">The <see cref="System.Type"/> of the class method's second parameter.</typeparam>
        /// <typeparam name="TArg3">The <see cref="System.Type"/> of the class method's third parameter.</typeparam>
        /// <typeparam name="TArg4">The <see cref="System.Type"/> of the class method's fourth parameter.</typeparam>
        /// <typeparam name="TArg5">The <see cref="System.Type"/> of the class method's fifth parameter.</typeparam>
        /// <typeparam name="TResult">The <see cref="System.Type"/> of the method result.</typeparam>
        /// <param name="func">The class method you want to memoize.</param>
        /// <param name="arg1">The value of the class method's first parameter.</param>
        /// <param name="arg2">The value of the class method's second parameter.</param>
        /// <param name="arg3">The value of the class method's third parameter.</param>
        /// <param name="arg4">The value of the class method's fourth parameter.</param>
        /// <param name="arg5">The value of the class method's fifth parameter.</param>
        /// <param name="durationInSeconds">The duration in seconds that you want to cache the method call result.</param>
        /// <returns>The memoized method's result data.</returns>
        public static TResult ResultOf<TArg1, TArg2, TArg3, TArg4, TArg5, TResult>(
            Func<TArg1, TArg2, TArg3, TArg4, TArg5, TResult> func,
            TArg1 arg1,
            TArg2 arg2,
            TArg3 arg3,
            TArg4 arg4,
            TArg5 arg5,
            long durationInSeconds)
        {
            var key = HashArguments(
                func.Method.DeclaringType.GUID,
                func.Method.Name,
                typeof(TArg1).GUID,
                (object)arg1,
                typeof(TArg2).GUID,
                (object)arg2,
                typeof(TArg3).GUID,
                (object)arg3,
                typeof(TArg4).GUID,
                (object)arg4,
                typeof(TArg5).GUID,
                (object)arg5);

            return Complete(key, durationInSeconds, () => func(arg1, arg2, arg3, arg4, arg5));
        }

        /// <summary>
        /// Memoize a call that takes 6 Parameters.
        /// </summary>
        /// <typeparam name="TArg1">The <see cref="System.Type"/> of the class method's first parameter.</typeparam>
        /// <typeparam name="TArg2">The <see cref="System.Type"/> of the class method's second parameter.</typeparam>
        /// <typeparam name="TArg3">The <see cref="System.Type"/> of the class method's third parameter.</typeparam>
        /// <typeparam name="TArg4">The <see cref="System.Type"/> of the class method's fourth parameter.</typeparam>
        /// <typeparam name="TArg5">The <see cref="System.Type"/> of the class method's fifth parameter.</typeparam>
        /// <typeparam name="TArg6">The <see cref="System.Type"/> of the class method's sixth parameter.</typeparam>
        /// <typeparam name="TResult">The <see cref="System.Type"/> of the method result.</typeparam>
        /// <param name="func">The class method you want to memoize.</param>
        /// <param name="arg1">The value of the class method's first parameter.</param>
        /// <param name="arg2">The value of the class method's second parameter.</param>
        /// <param name="arg3">The value of the class method's third parameter.</param>
        /// <param name="arg4">The value of the class method's fourth parameter.</param>
        /// <param name="arg5">The value of the class method's fifth parameter.</param>
        /// <param name="arg6">The value of the class method's sixth parameter.</param>
        /// <param name="durationInSeconds">The duration in seconds that you want to cache the method call result.</param>
        /// <returns>The memoized method's result data.</returns>
        public static TResult ResultOf<TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TResult>(
            Func<TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TResult> func,
            TArg1 arg1,
            TArg2 arg2,
            TArg3 arg3,
            TArg4 arg4,
            TArg5 arg5,
            TArg6 arg6,
            long durationInSeconds)
        {
            var key = HashArguments(
                func.Method.DeclaringType.GUID,
                func.Method.Name,
                typeof(TArg1).GUID,
                (object)arg1,
                typeof(TArg2).GUID,
                (object)arg2,
                typeof(TArg3).GUID,
                (object)arg3,
                typeof(TArg4).GUID,
                (object)arg4,
                typeof(TArg5).GUID,
                (object)arg5,
                typeof(TArg6).GUID,
                (object)arg6);

            return Complete(key, durationInSeconds, () => func(arg1, arg2, arg3, arg4, arg5, arg6));
        }

        /// <summary>
        /// Memoize a call that takes 7 Parameters.
        /// </summary>
        /// <typeparam name="TArg1">The <see cref="System.Type"/> of the class method's first parameter.</typeparam>
        /// <typeparam name="TArg2">The <see cref="System.Type"/> of the class method's second parameter.</typeparam>
        /// <typeparam name="TArg3">The <see cref="System.Type"/> of the class method's third parameter.</typeparam>
        /// <typeparam name="TArg4">The <see cref="System.Type"/> of the class method's fourth parameter.</typeparam>
        /// <typeparam name="TArg5">The <see cref="System.Type"/> of the class method's fifth parameter.</typeparam>
        /// <typeparam name="TArg6">The <see cref="System.Type"/> of the class method's sixth parameter.</typeparam>
        /// <typeparam name="TArg7">The <see cref="System.Type"/> of the class method's seventh parameter.</typeparam>
        /// <typeparam name="TResult">The <see cref="System.Type"/> of the method result.</typeparam>
        /// <param name="func">The class method you want to memoize.</param>
        /// <param name="arg1">The value of the class method's first parameter.</param>
        /// <param name="arg2">The value of the class method's second parameter.</param>
        /// <param name="arg3">The value of the class method's third parameter.</param>
        /// <param name="arg4">The value of the class method's fourth parameter.</param>
        /// <param name="arg5">The value of the class method's fifth parameter.</param>
        /// <param name="arg6">The value of the class method's sixth parameter.</param>
        /// <param name="arg7">The value of the class method's seventh parameter.</param>
        /// <param name="durationInSeconds">The duration in seconds that you want to cache the method call result.</param>
        /// <returns>The memoized method's result data.</returns>
        public static TResult ResultOf<TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TResult>(
            Func<TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TResult> func,
            TArg1 arg1,
            TArg2 arg2,
            TArg3 arg3,
            TArg4 arg4,
            TArg5 arg5,
            TArg6 arg6,
            TArg7 arg7,
            long durationInSeconds)
        {
            var key = HashArguments(
                func.Method.DeclaringType.GUID,
                func.Method.Name,
                typeof(TArg1).GUID,
                (object)arg1,
                typeof(TArg2).GUID,
                (object)arg2,
                typeof(TArg3).GUID,
                (object)arg3,
                typeof(TArg4).GUID,
                (object)arg4,
                typeof(TArg5).GUID,
                (object)arg5,
                typeof(TArg6).GUID,
                (object)arg6,
                typeof(TArg7).GUID,
                (object)arg7);

            return Complete(key, durationInSeconds, () => func(arg1, arg2, arg3, arg4, arg5, arg6, arg7));
        }

        /// <summary>
        /// Memoize a call that takes 8 Parameters.
        /// </summary>
        /// <typeparam name="TArg1">The <see cref="System.Type"/> of the class method's first parameter.</typeparam>
        /// <typeparam name="TArg2">The <see cref="System.Type"/> of the class method's second parameter.</typeparam>
        /// <typeparam name="TArg3">The <see cref="System.Type"/> of the class method's third parameter.</typeparam>
        /// <typeparam name="TArg4">The <see cref="System.Type"/> of the class method's fourth parameter.</typeparam>
        /// <typeparam name="TArg5">The <see cref="System.Type"/> of the class method's fifth parameter.</typeparam>
        /// <typeparam name="TArg6">The <see cref="System.Type"/> of the class method's sixth parameter.</typeparam>
        /// <typeparam name="TArg7">The <see cref="System.Type"/> of the class method's seventh parameter.</typeparam>
        /// <typeparam name="TArg8">The <see cref="System.Type"/> of the class method's eighth parameter.</typeparam>
        /// <typeparam name="TResult">The <see cref="System.Type"/> of the method result.</typeparam>
        /// <param name="func">The class method you want to memoize.</param>
        /// <param name="arg1">The value of the class method's first parameter.</param>
        /// <param name="arg2">The value of the class method's second parameter.</param>
        /// <param name="arg3">The value of the class method's third parameter.</param>
        /// <param name="arg4">The value of the class method's fourth parameter.</param>
        /// <param name="arg5">The value of the class method's fifth parameter.</param>
        /// <param name="arg6">The value of the class method's sixth parameter.</param>
        /// <param name="arg7">The value of the class method's seventh parameter.</param>
        /// <param name="arg8">The value of the class method's eighth parameter.</param>
        /// <param name="durationInSeconds">The duration in seconds that you want to cache the method call result.</param>
        /// <returns>The memoized method's result data.</returns>
        public static TResult ResultOf<TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TResult>(
            Func<TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TResult> func,
            TArg1 arg1,
            TArg2 arg2,
            TArg3 arg3,
            TArg4 arg4,
            TArg5 arg5,
            TArg6 arg6,
            TArg7 arg7,
            TArg8 arg8,
            long durationInSeconds)
        {
            var key = HashArguments(
                func.Method.DeclaringType.GUID,
                func.Method.Name,
                typeof(TArg1).GUID,
                (object)arg1,
                typeof(TArg2).GUID,
                (object)arg2,
                typeof(TArg3).GUID,
                (object)arg3,
                typeof(TArg4).GUID,
                (object)arg4,
                typeof(TArg5).GUID,
                (object)arg5,
                typeof(TArg6).GUID,
                (object)arg6,
                typeof(TArg7).GUID,
                (object)arg7,
                typeof(TArg8).GUID,
                (object)arg8);

            return Complete(key, durationInSeconds, () => func(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8));
        }

        /// <summary>
        /// Flushes the LocalCache of all Memoized method calls
        /// </summary>
        public static void Reset()
        {
            var enumerator = LocalCache.GetEnumerator();

            while (enumerator.MoveNext())
            {
                // We only want memoized items, don't flush the entire cache!
                if (enumerator.Key.ToString().Contains(MemoizeCacheKey))
                {
                    LocalCache.Remove(enumerator.Key.ToString());
                }
            }
        }

        private static T CacheResult<T>(string key, long durationInSeconds, T value)
        {
            LocalCache.Insert(
                key,
                value,
                null,
                DateTime.Now.AddSeconds(durationInSeconds),
                new TimeSpan());

            return value;
        }

        static T Complete<T>(string key, long durationInSeconds, Func<T> valueFunc)
        {
            return LocalCache.Get(key) != null
               ? (T)LocalCache.Get(key)
               : CacheResult(key, durationInSeconds, valueFunc());
        }

        /// <summary>
        /// A not completely foolproof way to generate a unique code to be used as a hash key in the LocalCache.
        /// </summary>
        /// <param name="args">All of the parameters you want a hash created against.</param>
        /// <returns>Hash key string.</returns>
        static string HashArguments(params object[] args)
        {
            if (args == null)
                return "null args";

            int result = 23;

            for (int i = 0; i < args.Length; i++)
            {
                var arg = args[i];

                if (arg == null)
                {
                    result = 31 * result + (i + 1);
                    continue;
                }

                result = 31 * result + arg.GetHashCode();
            }

            return MemoizeCacheKey + result.ToString();
        }
    }
}

Let’s create some class with a long running method

    public class SomeMath
    {
        public int Add(int a, int b)
        {
            // simulate a long running method
            System.Threading.Thread.Sleep(1000);

            return a + b;
        }
    }

You should now be able to see the difference running a test call

SomeMath math = new SomeMath();
int answer = 0;
// run method 1st time & prime cache
answer = Memoize.ResultOf<int, int, int>(math.Add, 1, 2, 100000);
// run method 2nd time, should be much faster
answer = Memoize.ResultOf<int, int, int>(math.Add, 1, 2, 100000);

Tags: , ,

 

Bad Behavior has blocked 56 access attempts in the last 7 days.