tags:

views:

57

answers:

4

In my program, there is a place when I need to access a singleton resolved from a factory and attach to its event:

void MyMethod()
{
   myFactory.Resolve<MySingleton>().DoWork += WorkMethod;
}

The problem is that MyMethod can be executed multiple times, but I want to attach to event only once (otherwise I'll get multiple calls). So I want to attach only when I wasn't attached before. It there anything nicier than

   myFactory.Resolve<MySingleton>().DoWork -= WorkMethod;
   myFactory.Resolve<MySingleton>().DoWork += WorkMethod;
+5  A: 

What about some flag to remember if MyMethod has already been called for the singleton?

object myCachedSingleton = null;

void MyMethod()
{
    var s = myFactory.Resolve<MySingleton>();
    if (myCachedSingleton == s) return;
    myCachedSingleton = s;
    myCachedSingleton.DoWork += WorkMethod;
}
dtb
you can put the event and 'hasBeenCalled' logic into a private method. I usually do this to remove it from MyMethod(). If you have many events it clutters up the original method.
TheSean
I think this is a good approach, but my singleton is not a "life-long" singleton. At times it can be re-created, so it looks like instead of the flag I should use a reference to it.
Sergey Aldoukhov
A: 

You could also look into the InvocationList to see if anything has been attached to the event.

Edited to use an Action so you don't need to pass in some magic string.

Example:

public bool IsAttached(Action<string> methodToCheck)
{
    SomeWork completed = DoWork;
    return completed.GetInvocationList().Any(m => m.Method.Name == methodToCheck.Method.Name);
}

Usage:

    var b = new FooBar();
    b.DoWork += b_OnWorkCompleted;
    b.DoWork += c_OnWorkCompleted;

    Console.WriteLine(b.IsAttached(c_OnWorkCompleted));
    Console.WriteLine(b.IsAttached(b_OnWorkCompleted));
    Console.WriteLine(b.IsAttached(FooBar));

Output would be true, true, false

Mark
+1  A: 

Depending on how coupled you want these types to be, you could attach to the event in a static constructor. Then it would only be possible to get executed a single time (per AppDomain I think). Something like this:

public class MyConsumer
{
    static MyConsumer()
    {
        Factory.Resolve<Singleton>().DoWork += WorkMethod;
    }

    private static void WorkMethod(...) { ... }
}

The (over) use of static methods is a little off-putting, but depending on your requirements that may be ok.

I'll just add that the other answers here are also fine, but make sure you think about any threading issues.

akmad
A: 

I just want to put the approach I used in the question for voting, too - if you disagree, vote it down...

Is there anything wrong with

var singleton = myFactory.Resolve<MySingleton>();
singleton.DoWork -= WorkMethod;   
singleton.DoWork += WorkMethod;

???

Sergey Aldoukhov