Isolate common code across generic functions

自古美人都是妖i 提交于 2019-12-24 06:49:28

问题


I have two functions in a class. The only differences are the parameter to the function (one taking a Func with a X and the other a Y) and the lines marked with asterisks.

Is there any way to isolate those two lines with asterisks or have a common function, or rewrite the functions such that the try, catch block and last few statements are written only once?

The objective here is to minimize code duplication.

public T Do<T>(Func<X, T> something)
{
    try
    {
        var manager = CoreInfrastructure.GetManager(Prefix, Config.Param1, Config.Param2); //******
        if (manager != null) return something(manager);
        LoggingHandler.LogWarning(LogTitle, $"manager ({this}) is null.");
    }
    catch (MyException exp)
    {
        ExceptionHandler.HandleRecoverableException(exp, LogTitle,
            $"query on manager ({this}) failed.");
    }

    var msg = $"failed to query using manager ({this})!";
    LoggingHandler.LogCritical(LogTitle, msg);
    throw new MyException(msg);
}


public T Do<T>(Func<Y, T> something)
{
    try
    {
        var manager = CoreInfrastructure.GetManager(Prefix, Config.Param3); //******
        if (manager != null) return something(manager);
        LoggingHandler.LogWarning(LogTitle, $"manager ({this}) is null.");
    }
    catch (MyException exp)
    {
        ExceptionHandler.HandleRecoverableException(exp, LogTitle,
            $"query on manager ({this}) failed.");
    }

    var msg = $"failed to query using manager ({this})!";
    LoggingHandler.LogCritical(LogTitle, msg);
    throw new MyException(msg);
}

回答1:


Create generic method that accepts manager and function

    public T Do<T, TManager>(TManager manager, Func<TManager, T> something)
    {
        try
        {
            if (manager != null) return something(manager);
            LoggingHandler.LogWarning(LogTitle, $"manager ({this}) is null.");
        }
        catch (MyException exp)
        {
            ExceptionHandler.HandleRecoverableException(exp, LogTitle,
                $"query on manager ({this}) failed.");
        }

        var msg = $"failed to query using manager ({this})!";
        LoggingHandler.LogCritical(LogTitle, msg);
        throw new MyException(msg);
    }

    public void DoAll<T>(Func<X, T> somethingX, Func<Y, T> somethingY)
    {
        Do(CoreInfrastructure.GetManager(Prefix, Config.Param1, Config.Param2), somethingX);
        Do(CoreInfrastructure.GetManager(Prefix, Config.Param3), somethingY);
    }

As Damien_The_Unbeliever mentioned if creating manager can be source of MyException you can add Func<TManager> instead of TManager manager:

    public T Do<T, TManager>(Func<TManager> managerCreate, Func<TManager, T> something)
    {
        try
        {
            TManager manager = managerCreate();
            if (manager != null) return something(manager);
            LoggingHandler.LogWarning(LogTitle, $"manager ({this}) is null.");
        }
        catch (MyException exp)
        {
            ExceptionHandler.HandleRecoverableException(exp, LogTitle,
                $"query on manager ({this}) failed.");
        }

        var msg = $"failed to query using manager ({this})!";
        LoggingHandler.LogCritical(LogTitle, msg);
        throw new MyException(msg);
    }

    public void DoAll<T>(Func<X, T> somethingX, Func<Y, T> somethingY)
    {
        Do(() => CoreInfrastructure.GetManager(Prefix, Config.Param1, Config.Param2), somethingX);
        Do(() => CoreInfrastructure.GetManager(Prefix, Config.Param3), somethingY);
    }

You can go further and replace Func<TManager> with parametrized function where you pass Prefix and Config




回答2:


We can create a private function that does the bulk of the work and make the existing methods just wrap it appropriately:

private T DoInternal<T>(Func<X> getManager, Func<X, T> something)
{
    try
    {
        var manager = getManager();
        if (manager != null) return something(manager);
        LoggingHandler.LogWarning(LogTitle, $"manager ({this}) is null.");
    }
    catch (MyException exp)
    {
        ExceptionHandler.HandleRecoverableException(exp, LogTitle,
            $"query on manager ({this}) failed.");
    }

    var msg = $"failed to query using manager ({this})!";
    LoggingHandler.LogCritical(LogTitle, msg);
    throw new MyException(msg);
}
public T Do<T>(Func<X, T> something)
{
    return DoInternal(()=> CoreInfrastructure.GetManager(Prefix, Config.Param1, Config.Param2), something);
}
public T Do<T>(Func<Y, T> something)
{
    return DoInternal(()=> CoreInfrastructure.GetManager(Prefix, Config.Param3),something);
}

Of course, getManager may need to be further parameterized if there's common functionality there (e.g. allow DoInternal to pass Prefix?).

(Also, the above declarations all look a little suspect being only parameterized in T and not X and Y. Some further adjustments may be required there)



来源:https://stackoverflow.com/questions/54037511/isolate-common-code-across-generic-functions

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!