Passing argument to an Action without using an anonymous function? - c#

Is there a way I can pass through an argument to an Action without using an anonymous function?
Eg, the following code works fine:
private void doSomethingAndLogIt(string log, Action dosomething)
{
Debug.WriteLine(log);
dosomething();
}
private void multiplyIt()
{
_result = "great";
}
...
doSomethingAndLogIt("Did something", multiplyIt);
but what I want to do is this:
private void doSomethingAndLogIt(string log, Action<int> dosomething)
{
Debug.WriteLine(log);
dosomething(???);
}
private void multiplyIt(int a)
{
_result = "great";
}
doSomethingAndLogIt("Did something", multiplyIt(5));
I realise that I can do this:
private void doSomethingAndLogIt(string log, Action<int> dosomething, int inputValue)
{
Debug.WriteLine(log);
dosomething(inputValue);
}
private void multiplyIt(int a)
{
_result = "great";
}
doSomethingAndLogIt("Did something", multiplyIt, 5);
but it's pretty confusing. I also realise that I can do this:
doSomethingAndLogIt("Did something", () => {
multiplyIt(5);
});
but it would be great if I could do this:
doSomethingAndLogIt("Did something", multiplyIt(5));

You do not need to do anything special. This code below:
doSomethingAndLogIt("Test", () => multiplyIt(5));
will already do what you are after. When the delegate is called, the parameter 5 will be passed in as well. Why? Because the callee will call your delegate, and you will call the method multiply with the argument 5.
Here is a quick test.

It isn't possible to do that as of the current version of C#, here's why...
Let's take your example (fake syntax)
public int MultiplyIt(int value)
{
//Do something that has side-effects
}
public void SomeMethod(Action<int> someAction<int>)
{
//Do something
someAction();
}
Now let's create an override of that method:
public void SomeMethod(int someValue)
{
//Do something
}
Now you call it:
SomeMethod(multiplyIt(5))
Which one does the compiler call?
Lets say you don't overload it (or that for some reason the compiler shouts an error if you do, but it is legal).
What then is the difference between these two calls?
SomeMethod(multiplyIt(5));
SomeMethod(() => multiplyIt(5));
Technically the first one runs multiplyIt before passing its value to SomeMethod. The second one multiplyIt may never be called, or it may alter something and then call it. That is an important distinction. If you add in some method to call it without the () => part, the developer can't know, without reading documentation, how the method call (and the action) are called. Is it a normal method call? The "special" delegate case? Who knows.
The () => isn't that much of a price to pay to be able to read a method and understand that you are passing in a delegate vs a value.

Related

Pass any function regardless of its parameters

Assuming that I have the following three methods
void Execute(<What to put here?> method)
{
method();
}
void Function1(string a) { ... }
void Function2(int a) { ... }
how can I pass the functions Function1 and Function2 with designated parameters to the Execute method?
e.g. like this
Execute(Function1("Foo"));
but above example is calling the function, I want it to be called only in the Execute method.
I hope it got clear, if it doesn't, I am looking for a way just like this:
void Execute(Action method)
{
method();
}
void Function3() { ... }
which can then be called like this:
Execute(Function3);
so that Function3 is called in the Execute method, not when invoking the Execute method.
I want to be able to do the same thing, but pass specific parameters to the Function3 method that should be used when it is invoked.
Simply make a lambda out of it:
Execute(() => Function1("Foo"));

How does a Function Reference differ from Action<T>

I ran into this situation yesterday and it has been gnawing at me. The compiler does not complain about using a reference to a function for my DoThis method when it calls for an Action which to my understanding is a delegate with a 'void' return type.
What is really going on with this Action parameter on the DoThis function?
public class testit
{
// Call DoThis with just a function reference. Should not work, but does.
public void DoThisThing1() {
DoThis(this.thing1);
}
// Call DoThis with an action. This is correct.
public void DoThisThing2() {
DoThis(new Action<string, string>(this.thing2));
}
private void DoThis(Action<string, string> thing)
{
// Do some common things here.
// Invoke Action
thing.Invoke("1", "2");
// Do other things.
}
private void thing1(string p1, string p2){}
private void thing2(string p1, string p2){}
}
If your question is why this works:
DoThis(this.thing1);
Then that is implicitly:
DoThis(new Action<string,string>(this.thing1));
(where the delegate type is inferred from the resolved method signature of DoThis)
Simply: the compiler fills in some things for us - syntactic sugar that has existed since C# 2. In C# 1.1, it wouldn't have compiled.

Use func method for an action also?

I created a method to abstract try/catch functionality. I have about 30 methods that have this exact same try/catch scenario. So I put it in one method:
private T Invoke<T>(Func<T> func)
{
try
{
return func.Invoke();
}
catch (Exception ex)
{
throw LogAndThrowFaultException(ex);
}
}
Now, most of the methods call it like this:
public IEnumerable<PingResponse> GetAllForPingRequest(PingRequest pingRequest)
{
return Invoke(() => PingResponseLogic.GetAllForPingRequest(pingRequest));
}
My issue is that I have just a couple of methods that call it without needing to return a value:
Invoke<void>(() => CustomVariableGroupLogic.Delete(customVariableGroup));
However, I can't use void there. The Invoke() method takes a func, but in this case it needs to be an action. I did some research and it looks like I may have to create another Invoke() method, but have it take an action. Those suggestions were from 2009 and 2010 though. Is it possible to somehow use my func method without having to create another Invoke() method like Invoke2()?
One quick and dirty solution would be to add default value after calling Delete method. It will be ignored anyway, if you don't assign result of the Invoke method to a variable. For instance, next code demonstrates this:
Invoke(() => {CustomVariableGroupLogic.Delete(customVariableGroup); return 0; });
You can see similar example proposed here,
If you have lots and lots of such calls, you can build a fancy wrapper, that will return Func for a given Action. Example:
Func<Action, Func<int>> wrap = action => () => {action(); return 0;};
now you can
Invoke(() => wrap(() => CustomVariableGroupLogic.Delete(customVariableGroup)));
but this goes a little bit close to lambda craziness
Inspired by pcm2:
you can create an overload to Invoke, that simply takes Action as a parameter, use solution proposed above to call implementation with Func<T>:
public void Invoke(Action action)
{
Invoke(() => {action(); return 0;});
}
now you simply can
Invoke(() => CustomVariableGroupLogic.Delete(customVariableGroup));
Could you not just create an overload of invoke?
public void Invoke<T>(Func<T> func){
return (T) InvokeInternal(func);
}
public void Invoke(Action action){
InvokeInternal(action);
}
If you'd then want both methods to do the exact same thing, and keeping things DRY, you could create a method like so:
private object InvokeInternal(System.Delegate #delegate)
{
try
{
return #delegate.DynamicInvoke();
}
catch (Exception ex)
{
throw LogAndThrowFaultException(ex);
}
}
And have both your overloads calling this method, appropriately casting the result, if any
Do you really have to func.Invoke()? Why not just func()?
Why isn't your Invoke static?
Depending on what LogAndThrowFaultException is doing, this could be pretty bad. Make sure that the exception stack is preserved by always setting the inner exception to ex.
But yes, you need a second function that returns void instead of T.
You can wrap the action into a func like so. Or you can create a convenience function that does the wrapping:
void Main()
{
Action<string> a = s => Console.WriteLine(s);
Invoke(() => { a(); return null; });
Invoke(s);
}
private void Invoke(Action a)
{
Invoke(() => { a(); return null; };
}

Different methods using Functors/Delegates in c#

I have a method that I call multiple times, but each time a different method with a different signature is called from inside.
public void MethodOne()
{
//some stuff
*MethodCall();
//some stuff
}
So MethodOne is called multiple times, each time with a different *MethodCall(). What I'm trying to do is something like this :
public void MethodOne(Func<> MethodCall)
{
//some stuff
*MethodCall;
//some stuff
}
but the Methods that are called each have a different return type and different parameters. Is there a way to do this using Functors? If not, how would I go about doing this?
Thank you!
You best bet would be to use the non-generic Action type (or MethodInvoker would be the same), i.e.
public void MethodOne(Action callback)
{
//some stuff
if(callback != null) callback();
//some stuff
}
From this you can call any method by wrapping it at the caller, i.e.
MethodOne(SimpleMethod); // SimpleMethod has no parameters and returns void
MethodOne(() => MoreComplexMethod(1, "abc")); // this one returns void
MethodOne(() => { MethodThatReturnsSomething(12); }); // anything you like
etc
You cannot call a function which requires parameters without supplying them, so the answer is "no, not possible"
Also, maybe you want the following:
void MethodOne(Action a)
{
// some stuff
a();
// some stuff
}
... // somewhere in the code
MethodOne((Action)(() => { DoSomethingOther(1, 2, 3); }));
MethodOne((Action)(() => { DoSomethingEvenDifferent(1, 2, 3, 4, 5); }));
Every delegate in .Net is an instance of a class derived from Delegate. So if you really wish to pass 'any' delegate to a method, you can pass it as Delegate
To invoke it, you need to use its DynamicInvoke method.
public void MethodOne(Delegate MethodCall)
{
//some stuff
//Assuming you now have the required parameters
//or add params object[] args to the signature of this method
object res = MethodCall.DynamicInvoke(args); //args is object[] representing the parameters
//some stuff
}
But this is not recommended as DynamicInvoke is slow and it does not offer any compile time safety. Probably you should revisit your design.
This is basically not possible. You could make MethodOne generic for the return type, and use a lambda that closes over its outside block instead of parameters:
static void Main(string[] args)
{
int parameterSubst = 1;
int result = MethodOne<int>(() => parameterSubst);
string result2 = MethodOne<string>(() =>
{
string s = parameterSubst.ToString();
s += "foo";
return s;
});
}
static T MethodOne<T>(Func<T> function)
{
return function();
}
As you can see, parameterSubst is used in the passed Func<T>s, but not as a parameter.

Argument type 'void' is not assignable to parameter type 'System.Action'

This is my test code:
class PassingInActionStatement
{
static void Main(string[] args)
{
var dsufac = new DoSomethingUsefulForAChange();
dsufac.Do(WriteToConsole);
dsufac.Do2(s => WriteToConsoleWithSomethingExtra("Test"));
dsufac.Do(WriteToConsoleWithSomethingExtra("Test")); // Does not compile
}
internal static void WriteToConsole()
{
Console.WriteLine("Done");
}
internal static void WriteToConsoleWithSomethingExtra(String input)
{
Console.WriteLine(input);
}
}
internal class DoSomethingUsefulForAChange
{
internal void Do(Action action)
{
action();
}
internal void Do2(Action<String> action)
{
action("");
}
}
The first 2 calls work but I am wondering why the 3rd one does not. I do not fancy the code inside Do2 as it seems strange that I have type type action("") in there in order to get it to work.
Could someone please explain the 2 things I do not understand please?
Why I can not write the third line like that with calling Do
Why I have to write action("") in order get it to work in Do2
dsufac.Do(WriteToConsoleWithSomethingExtra("Test"));
actually calls the function first (WriteToConsoleWithSomethingExtra("Test")) and then attempts to pass the result into Do. Since there is no result (void), it's not possible.
What you actually want is this:
dsufac.Do(() => WriteToConsoleWithSomethingExtra("Test"));
The inner part declares a function that takes nothing (the () => bit), which calls WriteToConsoleWithSomethingExtra("Test") when executed. Then your dsufac.Do call will receive an action, like it expects.
As for Do2 - you've declared it as taking Action<String>, which means that action is a function that takes one argument. You have to pass it a string. That string might be empty, like in your action("") example, or it might be passed in externally, as in something like this:
dsufac.Do3(WriteToConsole, "Test");
...
internal void Do3(Action<String> action, String str)
{
action(str);
}
In your code
dsufac.Do(WriteToConsoleWithSomethingExtra("Test"));
is interpreted like the following
var variable = WriteToConsoleWithSomethingExtra("Test");
dsufac.Do(variable);
As the return type of WriteToConsoleWithSomethingExtra("Test") is void, so you can not actually pass it to dsufac.Do(). That is why its not getting compiled. But for the first one
dsufac.Do(WriteToConsole);
you are not calling the function, rather you are passing it as a method group, which is later get invoked in the Do() method of dsufac object. But if you want to write the 3rd line as the 1st one, you can use
dsufac.Do(() => WriteToConsoleWithSomethingExtra("Test"));
Do expects an Action (i.e. method which take no parameters and returns no value). Hence WriteToConsoleWithSomethingExtra is not a valid fit - takes one string parameter.
Do2 accepts an Action<T> (i.e. method which takes in one T parameter and returns no value). Hence when you invoke the delegate/action you need to supply one parameter of type T, here String.

Categories

Resources