Generic Func<> as parameter to base method
I might be losing the plot, but I hope someone can point me in the right direction.
What am I trying to do?
I'm trying to write some base methods which take Func<> and Action so that these methods handle all of the exception handling etc. so its not repeated all over the place but allow the derived classes to specify what actions it wants to execute.
So far this is the base class.
public abstract class ServiceBase<T>
{
protected T Settings { get; set; }
protected ServiceBase(T setting)
{
Settings = setting;
}
public void ExecAction(Action action)
{
try
开发者_开发百科 {
action();
}
catch (Exception exception)
{
throw new Exception(exception.Message);
}
}
public TResult ExecFunc<T1, T2, T3, TResult>(Func<T1, T2, T3, TResult> function)
{
try
{
/* what goes here?! */
}
catch (Exception exception)
{
throw new Exception(exception.Message);
}
}
}
I want to execute an Action in the following way in the derived class (this seems to work):
public void Delete(string application, string key)
{
ExecAction(() => Settings.Delete(application, key));
}
And I want to execute a Func in a similar way in the derived class but for the life of me I can't seem to workout what to put in the base class.
I want to be able to call it in the following way (if possible):
public object Get(string application, string key, int? expiration)
{
return ExecFunc(() => Settings.Get(application, key, expiration));
}
Am I thinking too crazy or is this possible? Thanks in advance for all the help.
Firstly, what you're doing with exceptions here is probably a bad idea. A general catch of all exceptions is hardly ever what you want.
But as for generally what you're doing, you already solved the problem with Action
. For convenience you just need a refinement for Func
that calls the Action
version:
public static TResult ExecFunc<TResult>(Func<TResult> func)
{
TResult result = default(TResult);
ExecAction(() => result = func());
return result;
}
There is no need to provide a way to pass arguments through, because closures already solve that problem:
var someData = "Hi!";
var result = ExecFunc(() => SomeOtherMethod(someData));
// the lambda can close over the local variables of the outer scope
Note how I've made the method static, because it looks like ExecAction
could also be static, because it doesn't refer to any instance members. And if methods are static, maybe it would be clearer to move them into a separate static
class.
public void Delete(string application, string key)
{
ExecAction(() => Settings.Delete(application, key));
}
public object Get(string application, string key, int? expiration)
{
return ExecFunc(() => Settings.Get(application, key, expiration));
}
// ...
public TResult ExecFunc<TResult>(Func<TResult> func)
{
try
{
return func();
}
catch (Exception exception)
{
throw new Exception(exception.Message);
}
}
By the way, your exception handling looks a bit dodgy: Firstly, it's not considered good practice to catch Exception
itself. Consider catching more specific exceptions instead. Secondly, you're throwing a new exception in your catch
block, which means that you're losing the stacktrace etc from the original exception. You should use throw;
instead to rethrow the original exception. (This assumes that your catch
block is doing some sort of useful work. If all you're doing is catching and throwing then just ditch the try...catch
blocks altogether.)
public TResult ExecFunc<T1, T2, T3, TResult>(Func<T1, T2, T3, TResult> function, T1 t1Param, T2 t2Param, T3 t3Param)
{
try
{
return function(t1Param, t2Param, t3Param);
}
catch (Exception exception)
{
throw new Exception(exception.Message);
}
}
Then you call it like this:
public object Get(string application, string key, int? expiration)
{
return ExecFunc(Settings.Get, application, key, expiration);
}
public object Get(string application, string key, int? expiration)
{
object result = null;
ExecAction(() => result = Settings.Get(application, key, expiration));
return result
}
精彩评论