c#函数作为参数-重复方法结构

C# Function as parameter - Repeat method structure

本文关键字:方法 结构 -重 参数 函数      更新时间:2023-09-26

我有多个具有不同签名的方法,每个方法都有一个带有自定义日志异常的try-catch块。(多个控制器结构相同).

public class TestController : BaseController
{
    public static ActionResult One(int param1, string param2)
    {
        try
        {
            // Do something
        }
        catch (Exception e)
        {
            LogException(e.Message);
            AddModelError(e.Message);
        }
        return View("ViwName1");
    }
    public static ActionResult Two(Date param3, bool param4)
    {
        try
        {
            // Do something
        }
        catch (Exception e)
        {
            LogException(e.Message);
            AddModelError(e.Message);
        }
        return View("ViwName2");
    }
}

我想知道是否有一种方法可以避免每个方法的try-catch阻塞,并执行另一个

public class TestController : BaseController
{
    public static ActionResult One(int param1, string param2)
    {
        // Do something (*)
        // Call "ActionWithTryCatch" method that has a "function argument" to "Do something (*)"
    }
    public ActionResult ActionWithTryCatch(MyDelegate del, string viewName)
    {
        try
        {
            return del.Invoke();
        }
        catch (Exception e)
        {
            LogException(e.Message);
            AddModelError(e.Message);
        }
        return View(viewName);
    }
}

我该怎么做呢?我见过使用委托的例子,但我知道那是强类型的,所以没有找到这样做的方法。谢谢!

您所描述的模式接近于面向方面编程(AOP)的一种形式。然而,如果你只是想将特定的Try Catch错误处理逻辑应用到控制器上的所有操作,那么可能不值得你引入整个AOP框架。相反,您可以利用HandleErrorAttribute或覆盖控制器类的OnException方法。

例如,你可以这样写你的控制器:

public class TestController
{
    private TestService service;
    public TestController(TestService service)
    {
        this.service = service;
    }
    public ActionResult One(int param1, string param2)
    {
        this.service.MethodOne(param1, param2);
        return View("ViwName1");
    }
    public ActionResult Two(Date param3, bool param4)
    {
        this.service.MethodTwo(param3, param4);
        return View("ViwName2");
    }
    protected override void OnException(ExceptionContext filterContext)
    {
        LogException(filterContext.Exception.Message);
        AddModelError(filterContext.Exception.Message);
        var errorView = new ViewResult { ViewName = "~/Path/To/Error/View" };
        filterContext.Result = errorView;
    }
}

如果你想把它抽象出来,那么你可以把覆盖的OnException逻辑移到一个基控制器类中,然后让你所有的控制器都继承自基控制器。

如果你想看到MVC中统一错误处理的其他方法,那么也可以查看这个博客:https://dusted.codes/demystifying-aspnet-mvc-5-error-pages-and-error-logging

根据我的评论,如果你坚持实现你所描述的模式,你可以使用gilmishal的答案的修改版本。

public class TestController
{
    private TestService service;
    public TestController(TestService service)
    {
        this.service = service;
    }
    public ActionResult One(int param1, string param2)
    {
        return this.ActionWithTryCatch(() => this.service.MethodOne(param1, param2), "ViwName1");
    }
    public ActionResult Two(Date param3, bool param4)
    {
        return this.ActionWithTryCatch(() => this.service.MethodTwo(param3, param4), "ViwName2");
    }
    public IActionResult ActionWithTryCatch(Action action, string viewName)
    {
        try
        {
            action.Invoke();
        }
        catch (Exception e)
        {
            LogException(e.Message);
            AddModelError(e.Message);
        }
        return View(viewName);
    }
}

如果你需要在js中传递参数给这个函数,你创建的这个方法将不能正常工作-所以我假设你只调用无参数的方法。

在这种情况下,你可以用Func<IActionResult>代替MyDelegate

public TResult ActionWithTryCatch<TResult>(Func<TResult> del, string viewName)
{
    try
    {
        return del.Invoke();
    }
    catch (Exception e)
    {
        LogException(e.Message);
        AddModelError(e.Message);
        throw;
    }
}

这将更类似于您的javascript实现,并将在unhandledexception时返回500 HTTP结果。

你应该这样调用它,如果你想要IActionResult返回类型-

ActionWithTryCatch<IActionResult>(MethodThatReturnsIActionResult, viewName);

我建议您查看泛型