I am trying to get my head around the use of the Action delegate type for use in forcing a timeout when methods called in a 3rd party COM dll hang up. After much searching I find that I can use Action<> or Func<> and pass up to 4 generic parameters depending on whether the method called returns a parameter or not.
For this instance I wish to call a timeout on a series of methods that return void and take 2 parameters. What follows is the code that I am putting together, but I am unable to determine how to correctly code the BeginInvoke, I am prompted to place "T arg1" and "T arg2" but when I enter param1 or param2 VS2008 tells me that these values are indeterminate.
Here is the code as it is so far:
static void CallAndWait(Action<T, T> action, int timeout)
{
Thread subThread = null;
Action<T, T> wrappedAction = (param1, param2) =>
{
subThread = Thread.CurrentThread;
action(param1, param2);
};
IAsyncResult result = wrappedAction.BeginInvoke(param1, param2, null, null);
if (((timeout != -1) && !result.IsCompleted) &&
(!result.AsyncWaitHandle.WaitOne(timeout, false) || !result.IsCompleted))
{
if (subThread != null)
{
subThread.Abort();
}
//TODO: close external resource.
throw new TimeoutException();
}
else
{
action.EndInvoke(result);
}
}
Any ideas on what is wrong here would be much appreciated.
Below is a re-edited code based on the first comment
Thanks for the input so far. The following compiles. I just can't seem to get the syntax right in calling it.
public static void CallAndWait<T1, T2>(Action<T1, T2> action, int timeout)
{
Thread subThread = null;
T1 param1 = default(T1);
T2 param2 = default(T2);
Action<T1, T2> wrappedAction = (p1, p2) =>
{
subThread = Thread.CurrentThread;
action(param1, param2);
};
IAsyncResult result = wrappedAction.BeginInvoke(param1, param2, null, null);
if (((timeout != -1) && !result.IsCompleted) &&
(!result.AsyncWaitHandle.WaitOne(timeout, false) || !result.IsCompleted))
{
if (subThread != null)
{
subThread.Abort();
}
//TODO: close external resource.
throw new TimeoutException();
}
else
{
action.EndInvoke(result);
}
}
I am trying to test this by calling the following method with it:
public void LongTimeProcess(int a, string b)
{
Thread.Sleep(a);
}
But the following code is not correct:
Action<int, string> action = (s1, s2) => LongTimeProcess(s1, s2);
CallAndWait<int, string>(action(1500, "hello"), 500);
Updated code
I've posted the code for future reference by forum users. The code below appears to work.
The only point to check is that my unit test causes an exception to be thrown when calling the routine a second time on the same function at the point where we "action.EndInvoke(result)" as the result is not associated with the action. This is probably because my LongProcess is just a Thread.sleep, which in this instance will mean that it hasn't aborted by the time that my second call is made.
public static void CallAndWait<T1, T2>(Action<T1, T2> action, T1 arg1, T2 arg2, int timeout)
{
Thread subThread = null;
Action<T1, T2> wrappedAction = (p1, p2) =>
{
subThread = Thread.CurrentThread;
action(arg1, arg2);
};
IAsyncResult result = wrappedAction.BeginInvoke(arg1, arg2, null, null);
if (((timeout != -1) && !result.IsCompleted) &&
(!result.AsyncWaitHandle.WaitOne(timeout, false) || !result.IsCompleted))
{
if (subThread != null)
{
subThread.Abort();
}
//TODO: close external resource.
throw new TimeoutException();
}
else
{
action.EndInvoke(result);
}
}
At first it should probably be
static void CallAndWait<T>(Action<T, T> action, int timeout)
instead of
static void CallAndWait(Action<T, T> action, int timeout)
and if the parameters have different types even the following.
static void CallAndWait<T1, T2>(Action<T1, T2> action, int timeout)
But I don't think that is all. Going to look at it again.
UPDATE
Now I can see your problem ... you are calling the action when you try to call CallAndWait(). The call must be the following
CallWithTimeout.CallAndWait(action, 1500, "hello", 500);
instead of your call.
CallWithTimeout.CallAndWait<int, string>(action(1500, "hello"), 500);
So you have to change the method signature from
void CallAndWait<T1, T2>(Action<T1, T2> action, int timeout)
to
void CallAndWait<T1, T2>(Action<T1, T2> action, T1 arg1, T2 arg2, int timeout)
modify the body a bit and you should be done.
Related
What I want.
Invoke(Action action);
Invoke(Func func);
Invoke(Action action)
{
some action before
action()
some action after
}
Invoke(Func func)
{
some action before
res = func()
some action after
return res;
}
Call example:
Invoke(() => Tread.Sleep(1000));
var res = Invoke(() => return 5);
But in instead of Func there can be Func , Func <T,R> and so on.
The main idea is to wrap any code inside common blocks.
Reflection is possible.
I can write many methods like:
Invoke(Action<T> action)
{
some action before
action()
some action after
}
Invoke(Action<T,T1> action)
{
some action before
action()
some action after
}
Invoke(Action<T, T1, T2> action)
{
some action before
action()
some action after
}
but it is too annoying.
You can pass in an instance of Delegate to your method:
void Invoke(Delegate d, params object[] args)
{
// do soemthing beforehand
d.DynamicInvoke(args);
// do something aferwards
}
However you lose any type-safety and have to check the number and types of the args being passed yourself.
The solution depends on whether your Invoke method needs to modify the delegate's arguments or not.
If it does not, then you can persist type-safety like this:
void Invoke(Action action)
{
// some action before
action();
// some action after
}
TResult Invoke<TResult>(Func<TResult> func)
{
// some action before
TResult res = func();
// some action after
return res;
}
Then you can use lambda expressions if you need to close over the arguments:
Invoke(() => Thread.Sleep(1000));
int res = Invoke(() => int.Parse("5"));
If your Invoke method does modify the arguments, then that cannot be done in a type-safe way that accommodates any function.
Consider the following pseudo code:
TResult Foo<TResult>(Func<T1, T2,...,Tn, TResult> f, params object[] args)
{
TResult result = f(args);
return result;
}
The function accepts Func<> with unknown number of generic parameters and a list of the corresponding arguments. Is it possible to write it in C#? How to define and call Foo? How do I pass args to f?
You can use Delegate with DynamicInvoke.
With that, you don't need to handle with object[] in f.
TResult Foo<TResult>(Delegate f, params object[] args)
{
var result = f.DynamicInvoke(args);
return (TResult)Convert.ChangeType(result, typeof(TResult));
}
Usage:
Func<string, int, bool, bool> f = (name, age, active) =>
{
if (name == "Jon" && age == 40 && active)
{
return true;
}
return false;
};
Foo<bool>(f,"Jon", 40, true);
I created a fiddle showing some examples: https://dotnetfiddle.net/LdmOqo
Note:
If you want to use a method group, you need to use an explict casting to Func:
public static bool Method(string name, int age)
{
...
}
var method = (Func<string, int, bool>)Method;
Foo<bool>(method, "Jon", 40);
Fiddle: https://dotnetfiddle.net/3ZPLsY
That's not possible. At best, you could have a delegate that also takes a variable number of arguments, and then have the delegate parse the arguments
TResult Foo<TResult>(Func<object[], TResult> f, params object[] args)
{
TResult result = f(args);
return result;
}
Foo<int>(args =>
{
var name = args[0] as string;
var age = (int) args[1];
//...
return age;
}, arg1, arg2, arg3);
This could become easy with lambda expressions:
TResult Foo<TResult>(Func<TResult> f)
{
return f();
}
Then usage could be like:
var result = Foo<int>(() => method(arg1, arg2, arg3));
Where method can be arbitrary method returning int.
This way you can pass any number of any erguments directly through lambda.
To support asynchoronous code we can define:
Task<TResult> Foo<TResult>(Func<Task<TResult>> f)
{
return f();
}
// or with cancellation token
Task<TResult> Foo<TResult>(Func<CancellationToken, Task<TResult>> f, CancellationToken cancellationToken)
{
return f(cancellationToken);
}
and use it like:
var asyncResult = await Foo(async () => await asyncMethod(arg1, arg2, arg3));
// With cancellation token
var asyncResult = await Foo(
async (ct) => await asyncMethod(arg1, arg2, arg3, ct),
cancellationToken);
You could try something similar to what I posted here: https://stackoverflow.com/a/47556051/4681344
It will allow for any number of arguments, and enforces their types.
public delegate T ParamsAction<T>(params object[] args);
TResult Foo<TResult>(ParamsAction<TResult> f)
{
TResult result = f();
return result;
}
to call it, simply......
Foo(args => MethodToCallback("Bar", 123));
In some cases you may be able to get away with a trick like this:
public static class MyClass
{
private static T CommonWorkMethod<T>(Func<T> wishMultipleArgsFunc)
{
// ... do common preparation
T returnValue = wishMultipleArgsFunc();
// ... do common cleanup
return returnValue;
}
public static int DoCommonWorkNoParams() => CommonWorkMethod<int>(ProduceIntWithNoParams);
public static long DoCommonWorkWithLong(long p1) => CommonWorkMethod<long>(() => ProcessOneLong(p1));
public static string DoCommonWorkWith2Params(int p1, long p2) => CommonWorkMethod<string>(() => ConvertToCollatedString(p1, p2));
private static int ProduceIntWithNoParams() { return 5; }
}
Although it is not really what asked, a simple workaround would be to define several Foo method with different number of type arguments.
It is uncommon to have function with more than 6 parameters, so one could define the following method and get away with almost every use case, while staying type safe. Renan's solution could then be used for the remaining cases.
public TResult Foo<TResult> (Func<TResult> f)
{
return f();
}
public TResult Foo<T1, TResult>(Func<T1, TResult> f, T1 t1)
{
return f(t1);
}
public TResult Foo<T1, T2, TResult>(Func<T1, T2, TResult> f, T1 t1, T2 t2)
{
return f(t1, t2);
}
...
I want to use a list as storing actions to a framework while making async operations.
Then later when the framework synchronizes, then I will loop trought the list and perform the actions.
Is there a way to do this, with this in focus:
- No Reflection/DynamicInvoke.
- Not creating classes/structs for each new method to call.
- Type safe.
- store the actions in a list.
- store different kinds of methods and parameters.
- Execute the list later.
The reason I don't want to use reflection, is because it is a performance concern. It is gonna be use very frequently.
In this case, it is game related, but the code can be used as an allround, and would be excellent for multithreading, if reflection/DynamicInvoke could be avoided.
If this is not possible, then are there other nice alternatives?
I've made an example in code, but it uses reflection and isn't type safe.
Basicly the steps are:
1. Populate a list with methods with multiple different parameters.
2. Loop through the list & execute all methods with there parameters.
3. Clear the list for the next cycle.
{
struct MyDelayedCaller
{
public Delegate TheTarget;
public object[] MyParameters;
public MyDelayedCaller(Delegate target, object[] parameters)
{
TheTarget = target;
MyParameters = parameters;
}
}
List<MyDelayedCaller> Temporary = new List<MyDelayedCaller>();
void Update()
{
//something happened and another class needs to know
//but it will have to wait for the sync so as to not cause any treading problems
Temporary.Add(new MyDelayedCaller(new DelDoSomething1(DoSomething1), new object[] { 10, false }));
Temporary.Add(new MyDelayedCaller(new DelDoSomething1(DoSomething1), new object[] { 11, true }));
Temporary.Add(new MyDelayedCaller(new DelDoSomething3(DoSomething3), new object[] { "Some text" }));
Temporary.Add(new MyDelayedCaller(new DelDoSomething2(DoSomething2), new object[] { 1, 9999, 0.4f }));
}
void Sync()
{
foreach (var item in Temporary)
{
item.TheTarget.DynamicInvoke(item.MyParameters);
}
Temporary.Clear();
}
delegate void DelDoSomething1(int index, bool alive);
void DoSomething1(int index, bool alive)
{
}
delegate void DelDoSomething2(int index, int amount, float scale);
void DoSomething2(int index, int amount, float scale)
{
}
delegate void DelDoSomething3(string text);
void DoSomething3(string text)
{
}
}
I hope I understand the question because the answer seems so simple: Just store a List<Action>. You can put whatever you want in there. You can enumerate the list and call everything.
You absolutely can add parameterized calls to such a list: () => DoSomething1(10, false). The parameters are packaged inside of the Action. The C# compiler generates a (strongly-typed) closure class and does all of that for you.
Doesn't this do what you want?
I would go with following:
IMyDelayedCaller interface:
interface IMyDelayedCaller
{
void Invoke();
}
Set of MyDelayedCaller generic classes:
class MyDelayedCaller<T1> : IMyDelayedCaller
{
private Action<T1> _target;
public T1 _param;
public MyDelayedCaller(Action<T1> target, T1 parameter)
{
_target = target;
_param = parameter;
}
public void Invoke()
{
_target(_param);
}
}
class MyDelayedCaller<T1, T2> : IMyDelayedCaller
{
private Action<T1, T2> _target;
public T1 _param1;
public T2 _param2;
public MyDelayedCaller(Action<T1, T2> target, T1 param1, T2 param2)
{
_target = target;
_param1 = param1;
_param2 = param2;
}
public void Invoke()
{
_target(_param1, _param2);
}
}
I only showed for up to 2 parameters, you can make more if you need.
Change your list to List<IMyDelayedCaller>:
List<IMyDelayedCaller> Temporary = new List<IMyDelayedCaller>();
Add items to the list with compile time type safety:
Temporary.Add(new MyDelayedCaller<int, bool>(DoSomething1, 10, true));
Temporary.Add(new MyDelayedCaller<string>(DoSomething3, "Some text"));
Invoke using interface method:
foreach (var item in Temporary)
{
item.Invoke();
}
Temporary.Clear();
You can make stop 4. easier by providing static class which will allow your type parameters be inferred by compiler:
static class MyDelayedCaller
{
public static MyDelayedCaller<T1> Create<T1>(Action<T1> target, T1 param)
{
return new MyDelayedCaller<T1>(target, param1);
}
public static MyDelayedCaller<T1, T2> Create<T1, T2>(Action<T1, T2> target, T1 param1, T2 param2)
{
return new MyDelayedCaller<T1, T2>(target, param1, param2);
}
}
and usage:
Temporary.Add(MyDelayedCaller.Create(DoSomething1, 10, true));
Temporary.Add(MyDelayedCaller.Create(DoSomething3, "Some text"));
You could queue up your inputs and actions in parallel collections:
var actions = new Dictionary<int, Func<object[], object>>();
var inputs = new Dictionary<int, object[]>();
//when you want to store the action and it's input
int counter = 0;
object[] someObjects = new object[] {};
actions.Add(counter, x => { return x[0]; });
inputs.Add(counter, someObjects);
counter++;
//and then later when it's time to execute
foreach (var input in inputs)
{
actions[input.Key].Invoke(input.Value);
}
Alternatively, you could roll a class that stores both the input and the action, so the input is coupled to the action at execution time by something other than a matching dictionary key.
My other answer shows quite complicated way to do that. There is however one much easier. Why don't you make your list List<Action>?
List<Action> Temporary = new List<Action>();
void Update()
{
//something happened and another class needs to know
//but it will have to wait for the sync so as to not cause any treading problems
Temporary.Add(() => DoSomething1(1, true));
Temporary.Add(() => DoSomething3("Some text"));
}
void Sync()
{
foreach (var item in Temporary)
{
item.Invoke();
}
Temporary.Clear();
}
Should work just fine.
#Eli, you're getting 4's as the input value in your for loop because execution of the actions is deferred. When they actually execute, i = 4;
To avoid this, queue up your inputs.
I'd respond to your comment with a comment, but don't have the rep yet.
Inisde the callback after BeginInvoke, AsyncResult.AsyncDelegate needs to be cast to proper type, only then EndInvoke is accessible.
But I am using generics, so do I need to define N callbacks for N generalized methods?
This is the class:
public class Async
{
public delegate object Func(); //void with no parameter
public delegate TResult Func<T, TResult>(T arg); //one parameter with result
public static void Execute(IAsyncSubscriber subscriber, Func action)
{
action.BeginInvoke(Callback, subscriber);
}
public static void Execute<T, T1>(IAsyncSubscriber subscriber, T param, Func<T, T1> action)
{
action.BeginInvoke(param, Callback, subscriber);
}
private static void Callback(IAsyncResult ar)
{
AsyncResult result = (AsyncResult)ar;
IAsyncSubscriber subscriber = (IAsyncSubscriber)result.AsyncState;
Func action = (Func) result.AsyncDelegate;
object returnValue = action.EndInvoke(result); //To call endinvoke
subscriber.Callback(returnValue);
}
}
There are a few ways in which you can avoid defining N callbacks:
You can pass the corresponding EndInvoke method as state in the BeginInvoke call. e.g.
private delegate T EndInvokeDelegate<T>(IAsyncResult ar);
public static void Execute<T, T1>(IAsyncSubscriber subscriber, T param, Func<T, T1> action)
{
action.BeginInvoke(param, Callback<T1>, new object[]{subscriber, new new EndInvokeDelegate<T1>(action.EndInvoke)});
}
public static void Execute<T, T1, T2>(IAsyncSubscriber subscriber, T param1, T1 param2, Func<T, T1, T2> action)
{
action.BeginInvoke(param1, param2, Callback<T2>, new object[]{subscriber, new new EndInvokeDelegate<T2>(action.EndInvoke)});
}
private static void Callback<TR>(IAsyncResult ar)
{
object[] stateArr = (object[])ar.AsyncState;
IAsyncSubscriber subscriber = (IAsyncSubscriber)stateArr[0];
EndInvokeDelegate<TR> action = (EndInvokeDelegate<TR>)stateArray[1];
TR returnValue = action(ar);
subscriber.Callback(returnValue);
}
You can also make Callback non-generic by treating stateArray[1] as MultiCastDelegate and using DynamicInvoke on it but that would be slow.
For .Net 2.0 and 3.0, you can use reflection e.g.
Type actionType= result.AsyncDelegate.GetType();
var minfo = actionType.GetMethod("EndInvoke");
object returnValue = minfo.Invoke(res.AsyncDelegate, new object[] { ar });
For .Net 4.0, you can use dynamic. e.g.
dynamic action = result.AsyncDelegate;
object returnValue = action.EndInvoke(result);
If I understand correctly, your assumption is correct. You will need to define N callbacks.
On the bright side, you will only be doing this once, so no biggy, just a little repetitive work :)
I have several methods all returning void with different signature (parameters) and different names. I need to pass those methods as a parameter in a generic method that will invoke it latter. Also that need to be as transparent as possible.
Following what I got so far:
private void button1_Click(object sender, EventArgs e)
{
Action<string,int> TestHandler = Test;
InvokeMyMethod(TestHandler);
Action<string, int,object > TestHandlerN = TestN;
InvokeMyMethod(TestHandlerN);
}
public void InvokeMyMethod(Delegate Method)
{
object[] args = new object[X];
Method.DynamicInvoke();
}
public void Test(string t1, int t2)
{
MessageBox.Show(t1 + t2);
}
public void TestN(string t1, int t2, object t3)
{
MessageBox.Show(t1 + t2);
}
That is what I need:
private void button1_Click(object sender, EventArgs e)
{
InvokeMyMethod(Test);
InvokeMyMethod(TestN);
}
public void InvokeMyMethod(XXX_Type Method)
{
object[] args = new object[X];
Method.DynamicInvoke(args);
}
public void Test(string t1, int t2)
{
MessageBox.Show(t1 + t2);
}
public void TestN(string t1, int t2, object t3)
{
MessageBox.Show(t1 + t2);
}
This doesn't answer your question directly, but here is how I solve a similar problem:
public static partial class Lambda
{
public static Action Pin<T0>
(
this Action<T0> action,
T0 arg0
)
{
return () => action(arg0);
}
public static Func<TResult> Pin<T0, TResult>
(
this Func<T0, TResult> func,
T0 arg0
)
{
return () => func(arg0);
}
public static Action Pin<T0, T1>
(
this Action<T0, T1> action,
T0 arg0,
T1 arg1
)
{
return () => action(arg0, arg1);
}
public static Func<TResult> Pin<T0, T1, TResult>
(
this Func<T0, T1, TResult> func,
T0 arg0,
T1 arg1
)
{
return () => func(arg0, arg1);
}
// More signatures omitted for brevity...
// I would love it if C# supported variadic template parameters :-)
}
The idea is that if you have an Action which requires arguments, you can say:
Action<int, string> foo;
Action a = foo.Pin(5, "bleh");
Have the code generator.
Likewise, you might want to have a way to curry to some other delegate type (like Action<string, int>). The difference between my method and yours is that mine is not late-bound, but you do not appear to be using late-binding anyway, so early-binding gives you some compile-time type safety.
I'm not sure you can do what I think you are asking. You call method.DynamicInvoke with some object[], but how did you get values for those parameters?
And to answer the question before anybody asks it, I created the Lambda.Pin functions because I was tired of making this mistake:
Action<int> foo;
foreach (int i in someList)
AddAction(() => foo(i));
public void InvokeMyMethod(Delegate method) {
Method.DynamicInvoke(new object[] {"Test", 1});
}
But you need to invoke it like
InvokeMyMethod((Action<string, int>)Test);