I'm designing a class library that have a bunch of method of kind "EnsureXXX". The idea of this methods is to be called whenever a calling code requires something than can requires an initialization specific to the arguments. It's similar the EnsureChildControls method of ASP.Net, but with arguments as discriminators.
Ex:
public static class SomeUtilityClass {
    public static void EnsureSomething(string arg1, int arg2, object arg3)
    {
        // Logic should be called once for each args combination 
    }
}
public class CallerClass
{
    public void Foo()
    {
        SomeUtilityClass.EnsureSomething("mycustomerid", 4, myData.SomeProperty);
    }
    public void Foo2()
    {
        SomeUtilityClass.EnsureSomething("mycustomerid", 4, myData.SomeProperty);
    }
}
As such pattern will be reuse at several places and called very often, I have to keep performance as a target. I also have to have a thread-safe method.
For this purpose, I wrote a small utility class :
public sealed class CallHelper
{
    private static readonly HashSet<int> g_YetCalled = new HashSet<int>();
    private static readonly object g_SyncRoot = new object();
    public static void EnsureOnce(Type type, Action a, params object[] arguments)
    {
        // algorithm for hashing adapted from http://stackoverflow.com/a/263416/588868
        int hash = 17;
        hash = hash * 41 + type.GetHashCode();
        hash = hash * 41 + a.GetHashCode();
        for (int i = 0; i < arguments.Length; i++)
        {
            hash = hash * 41 + (arguments[i] ?? 0).GetHashCode();
        }
        if (!g_YetCalled.Contains(hash))
        {
            lock (g_SyncRoot)
            {
                if (!g_YetCalled.Contains(hash))
                {
                    a();
                    g_YetCalled.Add(hash);
                }
            }
        }
    }
}
The consuming code looks like this :
public static class Program
{
    static void Main()
    {
        SomeMethod("1", 1, 1);
        SomeMethod("2", 1, 1);
        SomeMethod("1", 1, 1);
        SomeMethod("1", 1, null);
        Console.ReadLine();
    }
    static void SomeMethod(string arg1, int arg2, object arg3)
    {
        CallHelper.EnsureOnce(typeof(Program), ()=>
        {
            Console.WriteLine("SomeMethod called only once for {0}, {1} and {2}", arg1, arg2, arg3);
        }, arg1, arg2, arg3);
    }
}
The output is, as expected :
SomeMethod called only once for 1, 1 and 1
SomeMethod called only once for 2, 1 and 1
SomeMethod called only once for 1, 1 and
I have some questions related to this approach :
- I think I have properly locked the class to ensure thread safety, but am I right ?
- Is HashSet<int>and my method of computing the hash correct ? I'm especially wondering if thenullhandling is correct, and if I can "hash" anActiondelegate this way.
- My methods currently supports only static methods. How can I move to a instance compatible method (adding the instance as a discriminator) without memory leaking?
- Is there any way to avoid passing all arguments manually to the utility method (just specifying the action), without exploring the stacktrace (because of the performance impact) ? I fear a lot of bugs introduced because of a missing arguments from the outermethod.
Thanks in advance
 
    