DRY具有不同的尝试语句和相同的捕获语句

时间:2013-06-26 21:12:51

标签: c# exception-handling dry

所以我在方法中有以下代码块:(所有变量都是本地的)

// ...

try
{
    if (postXml != null)
        using (StreamWriter writer = new StreamWriter(req.GetRequestStream()))
            writer.Write(postXml.ToString());
}
catch (WebException ex)
{
    HttpWebResponse response = ex.Response as HttpWebResponse;
    if (response != null)
        result = HandleOtherResponse(response, out status);
    else result = HandleBadResponse(ex.ToString(), out status);
}
catch (Exception ex)
{
    result = HandleBadResponse(ex.ToString(), out status);
}

if (result == null)
{
    try
    {
        HttpWebResponse response = req.GetResponse() as HttpWebResponse;
        result = HandleOtherResponse(response, out status);
    }
    catch (WebException ex)
    {
        HttpWebResponse response = ex.Response as HttpWebResponse;
        if (response != null)
            result = HandleOtherResponse(response, out status);
        else result = HandleBadResponse(ex.ToString(), out status);
    }
    catch (Exception ex)
    {
        result = HandleBadResponse(ex.ToString(), out status);
    }
}

// ...

如您所见,两个try语句不同,但两组catch语句完全相同。我一直试图想出一种可能不会在这里重复自己的方式,但我并没有想到一种不会显着变慢或者看起来很糟糕的方式。想知道是否有人有任何想法。

3 个答案:

答案 0 :(得分:5)

一种方法是写一个" safe"调用方法并将func传递给它:

public T SafeInvocation(Func<T> myMethod)
{
    T result = default(T);

    try
    {
        // Invoke method
        result = myMethod();
    }
    catch
    {
        // Do your common catch here
    }

    return result;
}

为Action&lt; T&gt;构建额外的重载这样你就不需要有一个返回类型。然后你可以在别处调用它,将方法作为参数传递给你的方法(Inception?):

SafeInvocation(() => 
{
    if (postXml != null)
        using (StreamWriter writer = new StreamWriter(req.GetRequestStream()))
            writer.Write(postXml.ToString());
}

答案 1 :(得分:0)

您可以将Action传递给处理异常的函数:

private void HandleErrorsFor(Action action)
{
    try
    {
        action();
    }
    catch (Exception ex)
    {
        //repeated exception handling...
    {
}

//...

public void DoSomething()
{
    HandleErrorsFor(() => {
        //try block #1
    });

    HandleErrorsFor(() => {
        //try block #2
    });
}

阅读起来更容易,避免重复编码。

答案 2 :(得分:0)

您可以对代理人执行某些操作并涵盖trycatch块:

  static class Program
  {
      delegate void CodeBlock();

      internal delegate void ExceptionCatcher(Exception ex);


    private static void Main()
    {
        CodeBlock b = () => { Console.WriteLine("HELLO WORLD"); };
        CodeBlock error = () => { throw new Exception("Exception thrown"); };
        ExceptionCatcher silence = exception => { };
        ExceptionCatcher e = exception =>
            {
                var currentColor = Console.BackgroundColor;
                Console.BackgroundColor = ConsoleColor.Red;
                Console.WriteLine(exception.Message);
                Console.BackgroundColor = currentColor;
            };

        DRYRunner(b, e);
        DRYRunner(error , e);
        DRYRunner(error , silence);

        Console.ReadLine();
    }

    static void DRYRunner (CodeBlock block, ExceptionCatcher catcher)
    {
        try
        {
            block.Invoke();
        }
        catch (Exception ex)
        {
            catcher(ex);
        }
    }
}   

编辑:扩展这一点,我们可以创建一个类来帮助包含代码块并将其与可能的异常和处理程序相关联。您甚至可以创建一类公共异常处理程序并相应地引用它们,将它们与ad-hoc处理程序混合使用:

 class ExceptionHandledDelegate
{
    public delegate void CodeBlock();

    public delegate void ExceptionCatcher(Exception ex);

    public Dictionary<Type, ExceptionCatcher> ExceptionHandlers;

    public CodeBlock codeBlock { get; set; }

    public void Run()
    {
        try
        {
            codeBlock.Invoke();
        }
        catch (Exception ex)
        {
            var mn = ex.GetType();
            if (ExceptionHandlers.Keys.Contains(mn))
            {
                ExceptionHandlers[mn](ex);
            }
            else throw; 
        }

    }
}
class CommonHandlers
{
    public static void ArgumentHandler(Exception ex)
    {
        Console.WriteLine("Handling an argument exception");
    }

    public static void DivZeroHandler(Exception ex)
    {
        Console.WriteLine("Please don't divide by zero. It upsets the universe.");
    }
}
static class Program
{

    private static void Main()
    {
        var ehd = new ExceptionHandledDelegate
        {
            codeBlock = () => { throw new ArgumentException("An argument exception has been thrown"); },
            ExceptionHandlers = new Dictionary<Type, ExceptionHandledDelegate.ExceptionCatcher>
            {
                {typeof (ArgumentException), CommonHandlers.ArgumentHandler},
                {typeof (DivideByZeroException ),CommonHandlers.DivZeroHandler},
                {typeof (Exception), exception => Console.WriteLine("An exception has been thrown")}
            }
        };
        ehd.Run();
        ehd.codeBlock = () => { throw new Exception("An exception has been thrown"); };
        ehd.Run();
        ehd.codeBlock = () =>{var denom = 0; Console.WriteLine(100 / denom);};
        ehd.Run();
        Console.ReadLine();
    }
}