问题
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