Passing a method call and its parameter to a different method - c#

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.

Related

How to make a unversal timeoutable function wrapper in C#?

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;
}

Implement calling delegate with out parameters

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.

Passing a method with parameter Func<T> and getting TResult

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;
}

Calling a function using reflection that has a "params" parameter (MethodBase)

I have MethodBases for two functions:
public static int Add(params int[] parameters) { /* ... */ }
public static int Add(int a, int b) { /* ... */ }
I have a function that calls the MethodBases via a class I made:
MethodBase Method;
object Target;
public object call(params object[] input)
{
return Method.Invoke(Target, input);
}
Now if I AddTwoMethod.call(5, 4); it works fine.
If I however use AddMethod.call(5, 4); it returns:
Unhandled Exception: System.Reflection.TargetParameterCountException: parameters do not match signature
Is there any way to make it so that both calls work fine without need for manually putting the arguments in an array for the params int[]?
You could modify your call method to detect the params parameter and convert the rest of the input to a new array. That way your method could act pretty much the same as the logic C# applies to the method calling.
Something i quicly constructed for you (be aware that i tested this method in a pretty limited way, so there might be errors still):
public object call(params object[] input)
{
ParameterInfo[] parameters = Method.GetParameters();
bool hasParams = false;
if (parameters.Length > 0)
hasParams = parameters[parameters.Length - 1].GetCustomAttributes(typeof(ParamArrayAttribute), false).Length > 0;
if (hasParams)
{
int lastParamPosition = parameters.Length - 1;
object[] realParams = new object[parameters.Length];
for (int i = 0; i < lastParamPosition; i++)
realParams[i] = input[i];
Type paramsType = parameters[lastParamPosition].ParameterType.GetElementType();
Array extra = Array.CreateInstance(paramsType, input.Length - lastParamPosition);
for (int i = 0; i < extra.Length; i++)
extra.SetValue(input[i + lastParamPosition], i);
realParams[lastParamPosition] = extra;
input = realParams;
}
return Method.Invoke(Target, input);
}
Be aware that i tested this method in a pretty limited way, so there might be errors still.
Supposing we have the following example class:
public class Test
{
public static int Add(int i1, int i2)
{
return i1 + i2;
}
public static int Add(params int[] ints)
{
int sum = 0;
foreach (int i in ints)
sum += i;
return sum;
}
}
To get the MethodInfo objects for each overload of the static Add method you should do the following:
MethodInfo Add2Ints = typeof(Test).GetMethod("Add", new Type[] { typeof(int), typeof(int) });
MethodInfo AddParamsInts = typeof(Test).GetMethod("Add", new Type[] { typeof(int[]) });
In order to invoke any of the two methods, symply pass the arguments with the exact type expected by the specific overload you are invoking:
Add2Ints.Invoke(null, new object[] { 1, 2 });
AddParamsInts.Invoke(null, new object[] { new int[] { 1, 2 } });
Note that the following will not work:
AddParamsInts.Invoke(null, new object[] { 1, 2 });
because the signature of AddParmsInt is really (int[]) and although the compiler, as a courtesy, allows you to call such method as (int, int) under the hood what is really happening is that the call is converted for you at the call site to the equivalent (int[]) call. Via reflection you don't have the compiler's "help" so you need to pass the exact argument type defined by the method's signature.
With all that said, your call method should be as follows:
public object call(params object[] input)
{
return AddParamsInts.Invoke(null /*static*/, new object[] { input.Cast<int>().ToArray() });
}
Note that you can not directly cast a object[] array to a int[] array: int[] ints = (int[])input. Casting reference typed arrays to value-type arrays is not allowed.
Also important to note is that the defined overloads of the Add method are useless, as they overlap. Consider only using the params overload or, in case you want to guarantee that at least two arguments are needed in order to evaluate an addition, overload them the following way:
public int Add(int i1, int i2) { }
public int Add(int i1, int i2, params int[] args) { }
You should wrap the arguments in an array, but the compiler will be confused, so you need to help it a bit:
Eg:
AddMethod.call((object) new int[] {5, 4 });

How can i make params `out` in C#?

I find myself in the situation requiring this
public static void Fill(this SomeClass c, params out object[] p)
and calling it as
c.Fill(out i, out i2, out sz, out i3, out sz2);
However i get the error error CS1611: The params parameter cannot be declared as ref or out
How can i pass in variable length arguments and make them writeable? All of these are a mixture of ints and strings
You can't have it treat the arguments as out (or ref) and make use of the params feature at the same time. It simply doesn't work. The best you can do is to create an array parameter, make the array out, declare an array variable and call the method passing the array, then inspect each element manually by index.
Foo(out object[] data) {...}
object[] result;
Foo(out result);
// look at result[0], result[1], result[2] etc
So: you cannot do what you want. Even if you could, ref / out never work unless there is an exact match between data type, so it would still have to be:
object o1, o2, o3, o4;
Foo(out o1, out o2, out o3, out o4);
// cast o1, o2, o3, o4
Which still isn't what you want.
There is no technical need for out here. This works:
void Fill(object[] p)
{
p[0] = 1;
p[1] = 42;
p[2] = "Hello";
p[3] = -1;
p[4] = "World";
}
object[] p = new object[5];
foo.Fill(p);
i = (int)p[0];
i2 = (int)p[1];
sz = (string)p[2];
i3 = (int)p[3];
sz2 = (string)p[4];
You could return your values as Tuple:
(define your own tuple class if you're not using .NET4.0)
static Tuple<int, string> Fill()
{
return new Tuple(42, "Hello World");
}
and then define extension methods to unpack tuples:
public static class TupleExtensions
{
public static void Unpack<T1, T2>(
this Tuple<T1, T2> tuple,
out T1 item1,
out T2 item2)
{
item1 = tuple.Item1;
item2 = tuple.Item2;
}
}
Then you can write this:
int i;
string sz;
foo.Fill().Unpack(out i, out sz);
1) If you can avoid the need to get the values in declared variables, then passing the array and populating it is the best option, as shown by dtb's answer.
2) Otherwise you can have a simple wrapper for your variable.
public class Wrapper //or may be generic?
{
public object Value { get; set; }
public Wrapper(object value)
{
Value = value;
}
}
Now you can call
var i = new Wrapper(0), i2 = new Wrapper(0), i3 = new Wrapper(0);
c.Fill(i, i2, i3);
i.Value //your value here
public static void Fill(this SomeClass c, params Wrapper[] p)
{
for (int i = 0; i < p.Length; i++)
{
p[i].Value = 1; //assigning
}
}
You will have to deal with Value property after calling Fill method.
3) You can make use of closure. Something like the Ref<T> class implemented as shown:
public static class Ref
{
public static Ref<T>[] Create<T>(params Expression<Func<T>>[] getters)
{
return getters.Select(Create).ToArray();
}
public static Ref<T> Create<T>(Expression<Func<T>> getter)
{
return new Ref<T>(getter);
}
}
public sealed class Ref<T>
{
readonly Func<T> getter;
readonly Action<T> setter;
public Ref(Expression<Func<T>> getter)
{
var output = getter.Body;
var input = Expression.Parameter(output.Type); //or hardcode typeof(T)
var assign = Expression.Assign(output, input);
var setter = Expression.Lambda<Action<T>>(assign, input);
this.getter = getter.Compile();
this.setter = setter.Compile();
}
public T Value
{
get { return getter(); }
set { setter(value); }
}
}
public static void Fill(this SomeClass c, params Ref<object>[] p)
//assign inside
object i = 0, i2 = 0, i3 = 0;
c.Fill(Ref.Create(() => i, () => i2, () => i3));
//i, i2 etc changed
Few things to note:
All the above approaches are basically ref approaches, compiler doesn't simply force assigning value of parameters inside the method before the control leaves as in the case of out which is your question, but as far as I know out is not possible here.
I like the first one, simple, and conventional. If not possible my vote is for 3rd approach.
As others have talked about, you can only pass the exact same type as ref/out parameters. So if your method by definition takes arbitrary references of object type, you have to declare even your variables as object locally. In the last approach, you can make the whole thing generic like by changing parameter type to Ref<T> from Ref<object> but that means your all local variables should also be one T.
You can use a dictionary structure to cache Ref<T> to avoid recompiling same trees.
The same implementation can be used to pass properties and variables as method arguments or return values by reference.
As others have said, you can't use params and out together. You have to construct an array at the call site.
This is because params tells the compiler to do the same thing - construct an array from the specified arguments. Unfortunately, when the compiler creates the array, you don't get a reference to it; even if the variable is written with a new array, you can never get to it.
I would guess you are asking for a thin metal ruler. What problem are you trying to solve with this mechanism?
I think I might have an answer to your question; Consider the following code snippet, with the main "InvokeMemberMethod" function doing the job you ask for. I encountered the same problem as you and came up with this solution:
Note: the "isOutXX" parameter specifies if the preceeding parameter is an "out" parameter.
static object InvokeMemberMethod(object currentObject, string methodName, int argCount,
ref object arg1, bool isOut1,
ref object arg2, bool isOut2,
ref object arg3, bool isOut3,
ref object arg4, bool isOut4,
ref object arg5, bool isOut5,
ref object arg6, bool isOut6)
{
if (string.IsNullOrEmpty(methodName))
{
throw new ArgumentNullException("methodName");
}
if (currentObject == null)
{
throw new ArgumentNullException("currentObject");
}
Type[] argTypes = null;
object[] args = null;
if (argCount > 0)
{
argTypes = new Type[argCount];
args = new object[argCount];
argTypes[0] = arg1.GetType();
if (isOut1)
{
argTypes[0] = arg1.GetType().MakeByRefType();
}
args[0] = arg1;
if (argCount == 2)
{
argTypes[1] = arg2.GetType();
if (isOut2)
{
argTypes[1] = arg2.GetType().MakeByRefType();
}
args[1] = arg2;
}
if (argCount == 3)
{
argTypes[2] = arg3.GetType();
if (isOut3)
{
argTypes[2] = arg3.GetType().MakeByRefType();
}
args[2] = arg3;
}
if (argCount == 4)
{
argTypes[3] = arg4.GetType();
if (isOut4)
{
argTypes[3] = arg4.GetType().MakeByRefType();
}
args[3] = arg4;
}
if (argCount == 5)
{
argTypes[4] = arg5.GetType();
if (isOut5)
{
argTypes[4] = arg5.GetType().MakeByRefType();
}
args[4] = arg5;
}
if (argCount == 6)
{
argTypes[5] = arg6.GetType();
if (isOut6)
{
argTypes[5] = arg6.GetType().MakeByRefType();
}
args[5] = arg6;
}
}
MethodInfo methodInfo = currentObject.GetType().GetMethod(methodName, argTypes);
int retryCount = 0;
object ret = null;
bool success = false;
do
{
try
{
//if (methodInfo is MethodInfo)
{
Type targetType = currentObject.GetType();
ParameterInfo[] info = methodInfo.GetParameters();
ParameterModifier[] modifier = new ParameterModifier[] { new ParameterModifier(info.Length) };
int i = 0;
foreach (ParameterInfo paramInfo in info)
{
if (paramInfo.IsOut)
{
modifier[0][i] = true;
}
i++;
}
ret = targetType.InvokeMember(methodName, BindingFlags.InvokeMethod, null, currentObject, args,
modifier, null, null);
//ret = ((MethodInfo)methodInfo).Invoke(currentObject, args,);
success = true;
}
//else
{
// log error
}
}
catch (TimeoutException ex)
{
}
catch (TargetInvocationException ex)
{
throw;
}
retryCount++;
} while (!success && retryCount <= 1);
if (argCount > 0)
{
if (isOut1)
{
arg1 = args[0];
}
if (argCount == 2)
{
if (isOut2)
{
arg2 = args[1];
}
}
if (argCount == 3)
{
if (isOut3)
{
arg3 = args[2];
}
}
if (argCount == 4)
{
if (isOut4)
{
arg4 = args[3];
}
}
if (argCount == 5)
{
if (isOut5)
{
arg5 = args[4];
}
}
if (argCount == 6)
{
if (isOut6)
{
arg6 = args[5];
}
}
}
return ret;
}
public int OutTest(int x, int y)
{
return x + y;
}
public int OutTest(int x, out int y)
{
y = x + 1;
return x+2;
}
static void Main(string[] args)
{
object x = 1, y = 0, z = 0;
Program p = new Program();
InvokeMemberMethod(p, "OutTest", 2,
ref x, false,
ref y, true,
ref z, false,
ref z, false,
ref z, false,
ref z, false);
}
You could pass an array by ref.
Edit:
This would of course change your calling method:
object[] array = new object[] { i, i2, sz, i3, sz2 };
c.Fill(ref array);
I don't imagine the original questioner needs this answer 11 years later, but I found this old question when searching for an overlapping requirement... and thinking through the answer to this question made me realise why my related one wouldn't work very neatly.
For this question, it was implied that the caller needs to communicate the number of parameters and their types to the Fill(...) function - how else does it match up the types to the calling site?
The intended syntax at the calling site could be achieved like this:
public class SomeClass { }
public static void Fill(this SomeClass c, Type[] outputTypes, out object[] p)
{
p = new object[outputTypes.Length];
// TODO: implementation to fill array with values of the corresponding types.
}
// this overload can be removed if "fill" of an empty array is meaningless.
public static void Fill(this SomeClass c)
{
c.Fill(new Type[0], out _);
}
public static void Fill<T>(this SomeClass c, out T r1)
{
c.Fill(new[] { typeof(T) }, out var p);
r1 = (T)p[0];
}
public static void Fill<T1, T2>(this SomeClass c, out T1 r1, out T2 r2)
{
c.Fill(new[] { typeof(T1), typeof(T2) }, out var p);
r1 = (T1)p[0];
r2 = (T2)p[1];
}
// ... extend as required depending on maximum number of out parameters that might be needed
// in particular the 5-parameter version is included in this sample to make OP's sample code line work.
public static void Fill<T1, T2, T3, T4, T5>(this SomeClass c, out T1 r1, out T2 r2, out T3 r3, out T4 r4, out T5 r5)
{
c.Fill(new[] { typeof(T1), typeof(T2), typeof(T3), typeof(T4), typeof(T5) }, out var p);
r1 = (T1)p[0];
r2 = (T2)p[1];
r3 = (T3)p[2];
r4 = (T4)p[3];
r5 = (T5)p[4];
}
public static void someFunction()
{
SomeClass c = new SomeClass();
int i, i2, i3;
string sz, sz2;
// the line below is exactly as shown in question.
c.Fill(out i, out i2, out sz, out i3, out sz2);
}

Categories

Resources