开发者

C#, how to avoid recursion elegantly?

I've got an event-function, where the code inside the function may trigger calling the same function again (because a message loop is used). How can I avoid this or better "detect" this most elegantly? When it comes to multiple thread synchronization one could write:

public void Closing(object sender, EventArgs e)
{
    lock(m_O开发者_运维知识库bject)
    {

        <Code, which can trigger Closing again>

    }
}

But in my case it is the same thread that may call the same function and thus lock fails to work.


Introduce a private bool m_IsClosing variable that indicates whether closing is already in progress.

public void Closing(object sender, EventArgs e)
{
    lock (m_Object)
    {
        if (m_IsClosing)
            return;

        m_IsClosing = true;

        try
        {    
            // Code, which can trigger Closing again
        }
        finally
        {        
            m_IsClosing = false;
        }
    }
}

I don't think it's particularly elegant, but without knowing more about what you're doing, I can't any better solution.

Edit: adapted example for possible exceptions while closing.


Add a member of your class closingInProgress initialized to false. Then:

public void Closing(object sender, EventArgs e)
{
    if (closingInProgress)
    {
        return;
    }

    try 
    {
         closingInProgress = true;
         <Code, which can trigger Closing again>
    } 
    finally 
    {
         closingInProgress = false;
    }
}


Use a private field to remember whether Closing has already been called. If it has, then abort from the procedure:

private bool ClosingDone;
public void Closing(object sender, EventArgs e)
{
    if (!ClosingDone)
    {
        ClosingDone = true;
        // Code, which can trigger Closing again
    }
}


A simple solution is to have a flag available in your class which indicates the event is being handled. Using this flag, you can determine whether to run the method again when called recursively.

private bool m_IsClosing;

public void Closing(object sender, EventArgs e)
{
    lock(m_Object)
    {
        // Check for state.
        if(m_IsClosing)
            return;

        m_IsClosing = true;

        try
        {
            // The rest of your code.
        }
        finally
        {
            m_IsClosing = false;
        }
    }
}

The only difficulty will be ensuring you don't read or modify this value elsewhere without entering a critical section locked on m_Object. Otherwise, it should prevent the event handler doing any work recursively.


It's a bit old, but how about that:

    public class Locker : IDisposable
{
    bool _isActive;
    public bool IsActive
    {
        get { return _isActive; }
    }

    private Locker()
    {
        _isActive = false;
    }

    public static Locker Create()
    {
        return new Locker();
    }


    public void Dispose()
    {
        _isActive = false;
    }


    public Locker Activate()
    {
        _isActive = true;
        return this;
    }
}

usage:

    Locker lo = Locker.Create();

    private void Foo()
    {
        if (lo.IsActive) return;
        using(lo.Activate())
        {
            Console.WriteLine("Foo");
            Bar();
        }
    }

    private void Bar()
    {
        Console.WriteLine("Bar");
        Foo();
    }

Method Foo() is only called once. using makes sure, that lo is deactivated, even if an error occures.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜