Reducing duplicate error handling code in C#?

后端 未结 4 1315
没有蜡笔的小新
没有蜡笔的小新 2020-12-29 19:08

I\'ve never been completely happy with the way exception handling works, there\'s a lot exceptions and try/catch brings to the table (stack unwinding, etc.), but it seems to

相关标签:
4条回答
  • 2020-12-29 19:14

    This looks like an excellent opportunity to have a look at Aspect Oriented Programming. Here is a good article on AOP in .NET. The general idea is that you'd extract the cross-functional concern (i.e. Retry for x hours) into a separate class and then you'd annotate any methods that need to modify their behaviour in that way. Here's how it might look (with a nice extension method on Int32)

    [RetryFor( 10.Hours() )]
    public void DeleteArchive()
    {
      //.. code to just delete the archive
    }
    
    0 讨论(0)
  • 2020-12-29 19:19

    Just wondering, what do you feel your method leaves to be desired? You could replace the anonymous delegate with a.. named? delegate, something like

        public delegate void IoOperation(params string[] parameters);
    
        public void FileDeleteOperation(params string[] fileName)
        {
            File.Delete(fileName[0]);
        }
    
        public void FileCopyOperation(params string[] fileNames)
        {
            File.Copy(fileNames[0], fileNames[1]);
        }
    
        public void RetryFileIO(IoOperation operation, params string[] parameters)
        {
            RetryTimer fileIORetryTimer = new RetryTimer(TimeSpan.FromHours(10));
            bool success = false;
            while (!success)
            {
                try
                {
                    operation(parameters);
                    success = true;
                }
                catch (IOException e)
                {
                    if (fileIORetryTimer.HasExceededRetryTimeout)
                    {
                        throw;
                    }
                    fileIORetryTimer.SleepUntilNextRetry();
                }
            }
        }
    
        public void Foo()
        {
            this.RetryFileIO(FileDeleteOperation, "L:\file.to.delete" );
            this.RetryFileIO(FileCopyOperation, "L:\file.to.copy.source", "L:\file.to.copy.destination" );
        }
    
    0 讨论(0)
  • 2020-12-29 19:27

    Here's what I did recently. It has probably been done elsewhere better, but it seems pretty clean and reusable.

    I have a utility method that looks like this:

        public delegate void WorkMethod();
    
        static public void DoAndRetry(WorkMethod wm, int maxRetries)
        {
            int curRetries = 0;
            do
            {
                try
                {
                    wm.Invoke();
                    return;
                }
                catch (Exception e)
                {
                    curRetries++;
                    if (curRetries > maxRetries)
                    {
                        throw new Exception("Maximum retries reached", e);
                    }
                }
            } while (true);
        }
    

    Then in my application, I use c#'s Lamda expression syntax to keep things tidy:

    Utility.DoAndRetry( () => ie.GoTo(url), 5);
    

    This calls my method and retries up to 5 times. At the fifth attempt, the original exception is rethrown inside of a retry exception.

    0 讨论(0)
  • 2020-12-29 19:29

    You could also use a more OO approach:

    • Create a base class that does the error handling and calls an abstract method to perform the concrete work. (Template Method pattern)
    • Create concrete classes for each operation.

    This has the advantage of naming each type of operation you perform and gives you a Command pattern - operations have been represented as objects.

    0 讨论(0)
提交回复
热议问题