Action delegate with more than four parameters (method arguments) - c#

I have written a helper class which uses the Action - delegate as method parameter.
Like this:
public void SomeMethod(Action<T> methodToExecute, T argument);
According to the MSDN you can declare max. 4 arguments on an action delegate: Action<T1,T2,T3,T4>.
Now I'd like to call a method which needs 5! arguments. How could I do this?
The best solution would be something where I could use a dynamic number of method arguments.
Thanks

Declare the action delegate you need, there's nothing magic about it:
public delegate void Action<T1, T2, T3, T4, T5>(T1 p1, T2 p2, T3 p3, T4 p4, T5 p5);

Related

How to convert delegate `Func<T1, Func<T2, Task<TResult>>>` to `Func<T1, Task<Func<T2, TResult>>`?

For my delegate (with signature Func<T1, Func<T2, Task<TResult>>) to be applicable it has to confirm to the signature Func<T1, Task<TResult>>. I would like to have a function such as:
public static Func<T1, Task<Func<T2, TResult>> TaskToOuterScope<T1, T2, TResult>(Func<T1, Func<T2, Task<TResult>>> f)
{
// throw new NotImplementedException();
}
How to implement this TaskToOuterScope-function?
I tried:
public static Func<T1, Task<Func<T2, TResult>> TaskToOuterScope<T1, T2, TResult>(Func<T1, Func<T2, Task<TResult>>> f)
{
return async (T1 arg1) => await (async (T2 arg2) => await f(arg1)(arg2));
}
However, this gives CS4001 Cannot await 'lambda expression'.
Googling gave pages that are either about currying (the signature Func<T1, Func<T2, Task<TResult>> is the result from currying) or about async/await but non about the combination or more specifically about moving task to outer scope in higher order functions.
Is conversion from Func<T1, Func<T2, Task<TResult>> to Func<T1, Task<Func<T2, TResult>>> possible?
And if so, how can I do it?
You can't.
Task<TResult> is a task whose result depends on two parameters, t1 and t2. You can see that you cannot transform it to a task Task<Func<T2, TResult>> whose result only depends on one parameter t1.
Whatever asynchronous task is being executed requires (by the definition you have given) those two parameters upfront before it starts executing. It cannot take t1 then, given t2 at a later point, return its result synchronously.

How to make T parameter available

I am writing an asynchronous class to simplify function operation. Below is my code:
using System;
namespace AsyncLibery
{
public class AsyncLibery
{
delegate void Exec(); // No input parameter, no return value
delegate void ExecWithParams<T>(T T1); //One input parameter, no return value
delegate void ExecWithParams<T1, T2>(T1 t1,T2 t2); //Two input parameters, no return value
delegate void ExecWithParams<T1, T2, T3>(T1 t1, T2 t2, T3 t3);//Three input parameters, no return value
delegate void ExecWithParams<T1, T2, T3, T4>(T1 t1, T2 t2, T3 t3, T4 t4);//Four input parameters,no return value
delegate T ExecWithReturnType<T>(); //No input parameter, one return value
delegate T2 ExecWithReturnType<T1, T2>(T1 t1); //One input parameter, one return value
delegate T3 ExecWithReturnType<T1, T2, T3>(T1 t1, T2 t2);//Two input parameters, one return value
delegate T4 ExecWithReturnType<T1, T2, T3, T4>(T1 t1, T2 t2, T3 t3);//Three input parameters, one return value
delegate T5 ExecWithReturnType<T1, T2, T3, T4, T5>(T1 t1, T2 t2, T3 t3, T4 t4);// Four input parameters, one return value.
#region no input parameter, no return value
public void BeginInvokeEx(Action actionFunction)
{
Exec exec = new Exec(actionFunction);
exec.BeginInvoke(new AsyncCallback(EndInvokeEx), exec);
}
private void EndInvokeEx(IAsyncResult iar)
{
Exec exec = (Exec)iar.AsyncState;
exec.EndInvoke(iar);
}
#endregion
#region one input parameter, no return value
public void BeginInvokeEx<T>(Action<T> actionFunction,T T1)
{
ExecWithParams<T> exec = new ExecWithParams<T>(actionFunction);
exec.BeginInvoke(T1, new AsyncCallback(EndInvokeEx1), exec);
}
private void EndInvokeEx1(IAsyncResult iar)
{
ExecWithParams<T> exec = (ExecWithParams<T>)iar.AsyncState;
exec.EndInvoke(iar);
}
#endregion
}
}
When I complied the code, it throws me an exception like "The type or namespace name 'T' could not be found (are you missing a using directive or an assembly reference?)", the exception is appeared at below code :
ExecWithParams<T> exec = (ExecWithParams<T>)iar.AsyncState;
I know that we must refer T parameter the specific type like int or string or anything else.
But who can help me without modifying the T parameter? is there any good method to deal with it?
thx.
Make EndInvokeEx1 generic:
private void EndInvokeEx1<T>(IAsyncResult iar)
{
ExecWithParams<T> exec = (ExecWithParams<T>)iar.AsyncState;
exec.EndInvoke(iar);
}
And change your BeginInvokeEx accordingly:
public void BeginInvokeEx<T>(Action<T> actionFunction,T T1)
{
ExecWithParams<T> exec = new ExecWithParams<T>(actionFunction);
exec.BeginInvoke(T1, new AsyncCallback(EndInvokeEx1<T>), exec);
}
You haven't defined what T is. You need to either have a generic parameter on the method EndInvokeEx1 such that it becomes EndInvokeEx<T>, where you can then pass T to the cast. Otherwise, it will need to be defined in the class declaration, so your class declaration becomes public class AsyncLibrary<T>. Otherwise, the compiler won't know what T is meant to represent.

How to declare a generic delegate with an out parameter [duplicate]

This question already has answers here:
Func<T> with out parameter
(4 answers)
Closed 9 years ago.
Func<a, out b, bool>, just don't compile, how to declare that i want the second parameter be an out one?
I want to use it like this:
public class Foo()
{
public Func<a, out b, bool> DetectMethod;
}
Actually, Func is just a simple delegate declared in the .NET Framework. Actually, there are several Func delegates declared there:
delegate TResult Func<TResult>()
delegate TResult Func<T, TResult>(T obj)
delegate TResult Func<T1, T2, TResult>(T1 obj1, T2 obj2)
delegate TResult Func<T1, T2, T3, TResult>(T1 obj1, T2 obj2, T3 obj3)
delegate TResult Func<T1, T2, T3, T4, TResult>(T1 obj1, T2 obj2, T3 obj3, T4 obj4)
delegate TResult Func<T1, T2, ... , T16, TResult>(T1 obj1, T2 obj2, ..., T16 obj16)
So the only thing you can do is declare your custom delegate:
delegate bool MyFunc<T1, T2>(T1 a, out T2 b)
You need to make your own delegate type, like this:
delegate bool MyFunc(Type1 a, out Type2 b);
You might want to rethink your design. Do you really need to complicate your code by adding an out parameter?
You can wrap the bool return type and the second out type in their own class (or .NET 4.0 Tuple) and use that as a return type:
public Func<Type1, Tuple<Type2, bool>> DetectMethod;
Of course when you want to use the delegates to reference try-parse methods, you are on the right track and you'll need to define a new delegate as others already described.

Func<T> with out parameter

Can I pass a method with an out parameter as a Func?
public IList<Foo> FindForBar(string bar, out int count) { }
// somewhere else
public IList<T> Find(Func<string, int, List<T>> listFunction) { }
Func needs a type so out won't compile there, and calling listFunction requires an int and won't allow an out in.
Is there a way to do this?
ref and out are not part of the type parameter definition so you can't use the built-in Func delegate to pass ref and out arguments. Of course, you can declare your own delegate if you want:
delegate V MyDelegate<T,U,V>(T input, out U output);
Why not create a class to encapsulate the results?
public class Result
{
public IList<Foo> List { get; set; }
public Int32 Count { get; set; }
}
The Func family of delegates (or Action for that matter) are nothing but simple delegate types declared like
//.NET 4 and above
public delegate TResult Func<out TResult>()
public delegate TResult Func<in T, out TResult>(T obj)
//.NET 3.5
public delegate TResult Func<T1, T2, TResult>(T1 obj1, T2 obj2)
public delegate TResult Func<T1, T2, T3, TResult>(T1 obj1, T2 obj2, T3 obj3)
etc. Delegates as such can have out/ref parameters, so in your case its only a matter of custom implementation by yourself as other answers have pointed out. As to why Microsoft did not pack this by default, think of the sheer number of combinations it would require.
delegate TResult Func<T1, T2, TResult>(T1 obj1, T2 obj2)
delegate TResult Func<T1, T2, TResult>(out T1 obj1, T2 obj2)
delegate TResult Func<T1, T2, TResult>(T1 obj1, out T2 obj2)
delegate TResult Func<T1, T2, TResult>(out T1 obj1, out T2 obj2)
for just two parameters. We have not even touched ref. It would actually be cumbersome and confusing for developers.
You could wrap it in a lambda/delegate/function/method that exposed the right interface and called FindForBar, but I suspect that FindForBar has count as an out parameter as a reason, so you'd need to be sure throwing that information away was ok/safe/desirable/had the right results (you'd need to be sure of this even if you could just directly pass in FindForBar).

Creating a reusable method timeout class in C#

I am trying to create a class that lets me call methods with a specified timout. I have the actual timeout implementation working, but am having trouble encapsulating this into a class successfully.
I have decided at this time to limit myself to working with just the 5 Action delegates to put a timeout on methods that take 0 - 4 arguments. For the purposes of this question i will use the one argument variant of Action.
My Ideal calling syntax would be something like this:
Action<int> a = new TimeoutAction(i => i + 1)
{
Timeout = Timespan.FromSeconds(10)
}
or this:
Action<int> a = (x => x + 1).Timeout(Timespan.FromSeconds(10))
I am almost sure that the first version isnt possible as there is no way to inherit from a delegate. The second may be possible by using an extension method on the Delegate type.
A final fallback would be to create static methods that take in the appropriate delegate type and return a Delegate with the same signature but with the timeouts included.
Any suggestions or ideas?
Your last suggestion would be the right way:
A final fallback would be to create
static methods that take in the
appropriate delegate type and return a
Delegate with the same signature but
with the timeouts included.
In other words:
public static Action<T> Timeout<T>(this Action<T> action, TimeSpan timeSpan);
public static Action<T1, T2> Timeout<T1, T2>(this Action<T1, T2> action, TimeSpan timeSpan);
public static Func<T, TResult> Timeout<T, TResult>(this Func<T, TResult> action, TimeSpan timeSpan);
public static Func<T1, T2, TResult> Timeout<T1, T2, TResult>(this Func<T1, T2, TResult> action, TimeSpan timeSpan);
/* snip the rest of the Action<...> and Func<...> overloads */
"Why can't I just declare one method?"
You could declare one method that accepts a Delegate and returns a Delegate, but then you'd lose the delegate type information (your second example wouldn't compile).
Unfortunately, the following example isn't valid C# -- you can't use Delegate as a type parameter constraint:
public static TDelegate Timeout<TDelegate>(this TDelegate d, Timespan timespan) where TDelegate : Delegate;
Use AOP for that. Either PostSharp or DynamicProxy
How about something like the approach to a Timed Lock as described here?
Well, a lambda expression won't "have a type" (anything you can 'dot' or extension method) until you wrap it in e.g.
new DelType(lambda)
or
Stat.Method(lambda)
or otherwise provide context, so I suggest the final option (static method):
Timeout.Action(lambda, timeoutVal)

Categories