I try to implement a decorator pattern for handling error in database transactions. I have no problem with standard Func and Actions, but i have difficulties with functions having out parameter.
Here many topics with same question, and i figured out to implement my own delegate:
public delegate TResult FuncWithOut<T1, T2, TResult>(T1 arg1, out T2 arg2);
1) But i don't found how to implement method based on this delegate:
private void SafetyExecuteMethod(Action action)
{
try
{
action();
}
catch (Exception ex)
{
// Some handling
}
}
private T SafetyExecuteFunction<T>(Func<T> func)
{
T result = default(T);
SafetyExecuteMethod(() => result = func.Invoke());
return result;
}
private SafetyExecuteFunctionWithOut // ??
{
// ??
}
2) And how to call this method:
public bool UserExists(string name)
{
return SafetyExecuteFunction(() => _innerSession.UserExists(name));
}
public void CreateUser(string name, string password)
{
SafetyExecuteMethod(() => _innerSession.CreateUser(name, password));
}
public bool CanUpdateUser(string userName, out string errorMessage)
{
// ??
// _innerSession.CanUpdateUser(userName, out errorMessage);
}
Just use the same scheme as in your example of SafetyExecuteFunction<T>(Func<T> func).
One thing you have to pay attention to is that you need to use a temporary local variable for the out parameter.
private TResult SafetyExecuteFunctionWithOut<T1, T2, TResult>(FuncWithOut<T1, T2, TResult> func, T1 arg1, out T2 arg2)
{
TResult result = default(TResult);
T2 arg2Result = default(T2); // Need to use a temporary local variable here
SafetyExecuteMethod(() => result = func(arg1, out arg2Result));
arg2 = arg2Result; // And then assign it to the actual parameter after calling the delegate.
return result;
}
Calling the function does then work like this:
public bool CanUpdateUser(string userName, out string errorMessage)
{
bool result = SafetyExecuteFunctionWithOut<string, string, bool>(_innerSession.CanUpdateUser, userName, out errorMessage);
return result;
}
Note, that you have to pass _innerSession.CanUpdateUser as a parameter to SafetyExecuteFunctionWithOut instead of using a lambda expression.
Using the naive attempt:
private TResult SafetyExecuteFunctionWithOut<T1, T2, TResult>(FuncWithOut<T1, T2, TResult> func, T1 arg1, out T2 arg2)
{
TResult result = default(TResult);
SafetyExecuteMethod(() => result = func(arg1, out arg2));
return result;
}
creates the error message:
CS1628 Cannot use ref or out parameter 'arg2' inside an anonymous
method, lambda expression, or query expression
Why you are not allowed to do that is explained in this answer.
Related
I have a bunch of functions with blocking calls which could hang in case of network connectivity loss or other issues. I want to make an universal wrapper allowing to run passed function with specified timout and arguments.
A function prototypes:
public static double Func1(string ip, string username, string password);
public static int Func2(string ip, string username, string password, string dir);
My wrapper:
public static T? ExecuteAsync<T>(Func<object[], T> func, int timeout /* sec */, params object[] args) where T : struct
{
var task = Task.Factory.StartNew(() => func(args));
if (task.Wait(timeout * 1000))
return task.Result;
return null;
}
Expected usage:
var res1 = ExecuteAsync<double>(Func1, 30, "1.1.1.1", "user", "looser");
var res2 = ExecuteAsync<int>(Func2, 20, "1.1.1.1", "user", "looser", "home");
Compiler errors here (on line with call to ExecuteAsync):
Error CS1503 Argument 1: cannot convert from 'method group' to 'Func'
I found a compilable code
var res = ExecuteAsync((args) => Func1(args[0].ToString(), args[1].ToString(), args[2].ToString()), 50, "ip", "user", "pass");
It is too heavy and unreadable. Is it possible to simplify it? How to fix original error? Maybe there is an another way to reach the goal?
I see examples with Action, but my functions are returning a value and they have different argument list.
The problem you have is the signature of Func1 has three string args whereas your ExecuteAsync method's first arg expects a "method" with object array as the argument
i.e. object[] != string, string, string
public static double Func1(string ip, string username, string password);
Func<object[], T>
The simplest solution you can have is to standardize the signature of all the "blocking functions". In that case your situation would look like below code. You lose type-safety in this. This approach is used by the Thread class
static void Main(string[] args) {
var res1 = ExecuteAsync<double>(Func1, 30, "1.1.1.1", "user", "looser");
}
public static double Func1(object[] args) {
string ip = (string)args[0], username = (string)args[1], password = (string)args[2];
// do some work
return 0.0;
}
public static T? ExecuteAsync<T>(Func<object[], T> func, int timeout /* sec */, params object[] args) where T : struct {
var task = Task.Factory.StartNew(() => func(args));
if (task.Wait(timeout * 1000))
return task.Result;
return null;
}
If you don't want to lose type safety, you can create multiple overloads of the ExecuteAsync method - similar to how .NET framework creates multiple overloads for Func. In that case, you ExecuteAsync method will look like below. You can create other overloads for 1, 2, 4, 5 arg methods just like how Func is implemented
public static TRes? ExecuteAsync<T1, T2, T3, TRes>(Func<T1, T2, T3, TRes> func, int timeout /* sec */, T1 arg1, T2 arg2, T3 arg3) where TRes : struct {
var task = Task.Factory.StartNew(() => func(arg1, arg2, arg3));
if (task.Wait(timeout * 1000))
return task.Result;
return null;
}
This question already has answers here:
Func<T> with out parameter
(4 answers)
Closed 6 years ago.
I have a service (3-rd party) with a lot of methods with signatures like:
int MethodA(int, string, out T result)
int MethodB(int, string, string, out T[] result)
int MethodC(DateTime, string, string, out T result)
Where returning int is just a response code, and I actually need T's.
After each call I have an error logging logic (basically calling error handling method with response code as argument).
I wanted something like:
private T GenericDataExtractor<T>(Func function) {
T result;
int responseCode = function(out result);
if(responseCode != 0)
/* handling here */
return result;
}
But there is no way to pass output parameter as argument to func.
UPDATE
As I mentioned in service example, it's important for me to pass delegate with generic arguments. In other words I want a method, that accepts a functions with different number of arguments, but with fixed return type and generic out parameter.
IN THE END
Well, I ended up with this solution:
protected delegate int KeeperAPIDelegate<TReturn>(string sessionID, out TReturn rObj);
protected delegate int KeeperAPIDelegate<T1, TReturn>(string sessionID, T1 obj1, out TReturn rObj);
protected delegate int KeeperAPIDelegate<T1, T2, TReturn>(string sessionID, T1 obj1, T2 obj2, out TReturn rObj);
protected delegate int KeeperAPIDelegate<T1, T2, T3, TReturn>(string sessionID, T1 obj1, T2 obj2, T3 obj3, out TReturn rObj);
protected TReturn DataGrabber<TReturn>(KeeperAPIDelegate<TReturn> action)
{
TReturn data;
int result = action.Invoke(SessionID, out data);
if (result == 0) return data;
throw HandleError(result);
}
protected TReturn DataGrabber<T1, TReturn>(KeeperAPIDelegate<T1, TReturn> action, params object[] args)
{
TReturn data;
int result = action.Invoke(SessionID, (T1)args[0], out data);
if (result == 0) return data;
throw HandleError(result);
}
protected TReturn DataGrabber<T1, T2, TReturn>(KeeperAPIDelegate<T1, T2, TReturn> action, params object[] args)
{
TReturn data;
int result = action.Invoke(SessionID, (T1)args[0], (T2)args[1], out data);
if (result == 0) return data;
throw HandleError(result);
}
protected TReturn DataGrabber<T1, T2, T3, TReturn>(KeeperAPIDelegate<T1, T2, T3, TReturn> action, params object[] args)
{
TReturn data;
int result = action.Invoke(SessionID, (T1)args[0], (T2)args[1], (T3)args[2], out data);
if (result == 0) return data;
throw HandleError(result);
}
Guess it's not optimal, so any suggestions how to improve this will be highly appritiated.
Func doesn't not support out parameters, but there is no problem with custom delegate
public delegate int MyFunction<T>(out T parameter);
private T GenericDataExtractor<T>(MyFunction<T> function, out T result){
T result;
int responseCode = function(out result);
if(responseCode != null) /* handling here */
//the if above is always true :)
return result;
}
So basically T has a return type, I want to get back the generic return type. Example:
private TResult EndInvoke<T, TResult>(Func<T, TResult> asyncCaller, IAsyncResult asyncResult)
{
TResult result = default(TResult);
try
{
result = asyncCaller.EndInvoke(asyncResult);
}
catch (Exception exception)
{
// get exception details.
}
return result;
}
How do I pass just the T calling the method and get the TResult?
Mind you, I only have the T.
EDIT: I meant how do I call this method?
EDIT: I want a generic EndInvoke, because I am a huge try catch on different EndInvokes, then I want the result from the EndInvoke.
I suggest converting your generic EndInvoke<,> method to an extension method first.
public static class FuncExtensions
{
public static TResult EndInvoke<T, TResult>(this Func<T, TResult> asyncCaller, IAsyncResult asyncResult)
{
// ...
}
}
This will simplify the method call. As an example, I'll call a method that calculates the square of an integer.
private int Square(int x)
{
return x * x;
}
In your client code, you'd call it like this:
Func<int, int> caller = new Func<int, int>(Square);
int x = 5;
int y = default(int);
caller.BeginInvoke(x,
asyncResult =>
{
y = caller.EndInvoke(asyncResult);
},
null);
Console.WriteLine("The square of {0} is {1}", x, y);
EDIT
This example has not been tested in any way, and contains an obvious race condition.
Not sure that I understand correctly, but I think that if you want the Func return value, you should drop the IAsyncResult.
Example:
private TResult GetResult<T, TResult>(Func<T, TResult> asyncCaller, IAsyncResult asyncResult)
{
TResult result = default(TResult);
result = asyncCaller(argument...);
return result;
}
Is it possible to use a TPL Task<TResult> to asynchronously invoke a thread-safe method with the following signature and retrieve the boolean return value and the output parameter?
public bool TryGet(T1 criteria,
out T2 output)
Obviously I can't use a lambda expression because of the output parameter. Additionally, I cannot solve the problem by defining a custom delegate such as below and passing that to the Task<TResult> constructor as I need to pass the criteria as a strongly typed parameter which the constructor does not support.
public delegate TResult Func<T1, T2, TResult>(T1 arg1,
out T2 arg2);
Is the best option to write a wrapper such as below and invoke that asynchronously instead?
public Tuple<bool, T2> TryGetWrapper(T1 criteria)
{
T2 output;
bool result = obj.TryGet(criteria,
out output);
return new Tuple<bool, T2>(result,
output);
}
Just seems a bit inelegant and has a bit of a whiff about it.
This is something I've also wrestled with.
I came up with a similar solution, except rather than use a Tuple I wrote a simple wrapper class, just to make things a bit more readable.
I'd also be interested to see any better solution - but what you propose seems as good as anything I came up with.
Here's what my wrapper class and its usage looks like. This is not an answer to your question; just a suggestion to (perhaps) make your solution a bit more readable.
(Although I concede that the Task<TryResult<DateTime>> declaration itself might not be considered all that readable!)
using System;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
internal class Program
{
static void Main()
{
string dateString = "Invalid Date";
var tryParseDateTask = new Task<TryResult<DateTime>>(() =>
{
DateTime result;
if (DateTime.TryParse(dateString, out result))
return TryResult<DateTime>.Success(result);
else
return TryResult<DateTime>.Failure();
});
tryParseDateTask.Start();
if (tryParseDateTask.Result.IsSuccessful)
Console.WriteLine(dateString + " was parsed OK.");
else
Console.WriteLine(dateString + " was parsed as " + tryParseDateTask.Result.Value);
}
}
public class TryResult<T>
{
public static TryResult<T> Success(T value)
{
return new TryResult<T>(value, true);
}
public static TryResult<T> Failure()
{
return new TryResult<T>(default(T), false);
}
TryResult(T value, bool isSuccessful)
{
this.value = value;
this.isSuccessful = isSuccessful;
}
public T Value
{
get
{
return value;
}
}
public bool IsSuccessful
{
get
{
return isSuccessful;
}
}
readonly T value;
readonly bool isSuccessful;
}
}
I think your approach is pretty much the best you can do. If you are doing this often, you could use a helper method that convert a delegate with out parameter to a Tuple-returning delegate (or something like TryResult-returning, as in Matthew Watson's answer):
public delegate TResult OutFunc<TIn, TOut, TResult>(TIn input, out TOut output);
public static Func<TIn, Tuple<TResult, TOut>> OutToTuple<TIn, TOut, TResult>(
OutFunc<TIn, TOut, TResult> outFunc)
{
return input =>
{
TOut output;
TResult result = outFunc(input, out output);
return Tuple.Create(result, output);
};
}
I am using an external automation library with bunch of APIs with either 1 or 2 parameters which randomly throws TargetInvocationException. Calling these APIs second or third time usually works. I therefore created two helper methods to encapsulate the multiple retry logic
//Original API calls
bool result1 = Foo1(true);
int result2 = Foo2(4, "abc");
//New API calls
bool result1 = SafeMethodCall(Foo1, true);
int result2 = SafeMethodCall(Foo2, 4, "abc");
//Helper Methods
public static TResult SafeMethodCall<T, TResult>(
Func<T, TResult> unSafeMethod,
T parameter)
{
int numberOfMethodInvocationAttempts = 3;
int sleepIntervalBetweenMethodInvocations = 10000;
for (int i = 0; i < numberOfMethodInvocationAttempts; i++)
{
try
{
return unSafeMethod(parameter);
}
catch (System.Reflection.TargetInvocationException ex)
{
System.Threading.Thread.Sleep(sleepIntervalBetweenMethodInvocations);
}
}
}
public static TResult SafeTargetInvocationMethodCall<T1, T2, TResult>(
Func<T1, T2, TResult> unSafeMethod,
T1 parameter1,
T2 parameter2)
{
int numberOfMethodInvocationAttempts = 3;
int sleepIntervalBetweenMethodInvocations = 10000;
for (int i = 0; i < numberOfMethodInvocationAttempts; i++)
{
try
{
return unSafeMethod(parameter1, parameter2);
}
catch (System.Reflection.TargetInvocationException ex)
{
System.Threading.Thread.Sleep(sleepIntervalBetweenMethodInvocations);
}
}
}
Problem: If you see the two helper methods above have the same body and the only difference is unsafeMethod call inside the try block. How can I avoid code duplication here as I might have to add a overloaded method that accepts
Func<TResult>
as another parameter type.
Just pass in Func<TResult> and call it like this:
bool result1 = SafeMethodCall(() => Foo1(true));
int result2 = SafeMethodCall(() => Foo2(4, "abc"));
In other words, encapsulate the arguments in the delegate itself.