Search code examples
c#design-patternssingletonusing

Detect in a not-involved class if call was wrapped in a using of another


Firstly, sorry for the difficult question title, but I can't think of anything better. If anybody knows a better description, I'd be happy to change the title! :)

Let's assume I have the following code with the two classes:

using(new Wrapper())
{
    Inner.Do();
}

public class Wrapper : IDisposable
{
    public static Wrapper Instance { get; set; }
    public Wrapper()
    {
        Instance = this;
    }

    public void Dispose()
    {
        Instance = null;
    }
}
public static class Inner
{
    public static Do()
    {
        if (Wrapper.Instance == null)
        { /* no using */ }
        else
        { /* with using */ }
    }
}

Above code works as intended, and I am able to detect whether or not my code was wrapped up in a using statement or not.

Unfortunately, a static Instance variable is the best way I can think of to achieve the above, but it's certainly not best-case. Assume that two Threads execute above code at the "same" time. One Thread would overwrite the Instance of the other, leading to unexcepted beaviour and race conditions.

Question:

Can anybody direct me to a solution where I am still able to do the above, but without the use of a static Instance variable?

Thanks in advance!

ANSWER

Since this is just a test for something new, I am now using the ThreadStaticAttribute. But as Marc Gravell stated out, don't use this if there are async operations going on.

For usage see Kris Vandermotten's answer.


Solution

  • Personally I would advise simply: not needing to do that. You are right in that there is no magic way to do that. The thread issue can be handled via [ThreadStatic], but that won't work well when multiple threads are involved, for example async. If possible, I would say: find a different implementation strategy that doesn't require detecting unrelated using blocks. Equally, your code would struggle to detect the difference between using and simply:

    new Wrapper(); // note this doesn't dispose cleanly
    Inner.Do();
    

    Another issue with some static instance is that you'd also need to consider multiple nested blocks; would need a Stack<Wrapper>, or you could cache the previous value to set it back to in the disposable object.