Use func method for an action also? - c#

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

Related

Passing argument to an Action without using an anonymous function?

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.

Using a setter as a parameter in C#? (Maybe with delegate?)

We're working on an API for some hardware and I'm trying to write some tests for it in C#. try-catch blocks for repetitive tasks were making my code bloated and repetitive so for getters I was able to wrap like this:
TestGetter(Func<int> method, double expectedVal)
{
int testMe = 0;
try
{
testMe = method();
PassIfTrue(testMe == expectedVal);
}
catch (Exception e)
{
Fail(e.Message);
}
}
So I query the hardware for some known value and compare. I can call with:
TestGetter( () => myAPI.Firmware.Version, 24); //Or whatever.
Which works quite well. But I'm not sure how to do the same with setters. Ie to ensure that the API actually set a value (and doesn't timeout or whatever when I try to set). I'd like to pass the setter to the test method and invoke it in there.
Bonus question: Is there a way to do this with a generic type? There are some custom types defined in the API and I'm not sure of a good way to write these test wrappers for them without writing a new overloaded method for every type. Thanks for any and all help!
You could pass the getter and the setter to the function:
void TestSetter<T>(Func<T> getter, Action<T> setter, T value)
{
try
{
setter(value);
PassIfTrue(EqualityComparer<T>.Default.Equals(getter(), value));
}
catch (Exception e)
{
Fail(e.Message);
}
}
This sets the value, then gets it and compares to the value passed to the setter.
You'd have to call it like:
TestSetter(() => myAPI.Firmware.Version, v => myAPI.Firmware.Version = v, 24);
You can make them generic like Reeds, but you need to use different comparison methods:
public static void TestGetter<T>(Func<T> method, T expectedVal)
{
try
{
T actual = method();
PassIfTrue(expectedVal.Equals(actual));
}
catch (Exception ex)
{
Fail(ex.Message);
}
}
public static void TestSetter<T>(Action setMethod, Func<T> getMethod, T expectedVal)
{
try
{
setMethod();
T actual = getMethod();
PassIfTrue(expectedVal.Equals(actual));
}
catch (Exception ex)
{
Fail(ex.Message);
}
}
You could also pass in a Comparer action to test them if you don't think the Equals method would work for the expected types.

Passing method to be executed asynch

I am creating a Windows forms application which executes a lot of similar operations on a piece of data. All these operations are almost the same so I would like to create a single method that
makes the user interface read-only
sets up messages like "Executing operation1..."
executes the operation asynchronously, so the user interface remains responsive
sets up message to "Operation1 finished."
Set interface read-only to false.
I imagine calling this single method like
ExecuteOperation([method to execute], "Executing operation1")
I am sure that this is simple but I am lost between delegates and tasks so please show me how to write a method that is capable of running a selected method, preferably with multiple parameters and how this method is called.
Note:
By disabling the interface I mean
MainMenu.Enabled = false;
txtData.ReadOnly = true;
You're probably looking for something like this (I've shown an example here for a method that takes parameters, since you asked for that case specifically):
private async Task ExecuteOperation(string operationName, Action action)
{
//Disable UI here
//Set 'Executing' message here
await Task.Run(action);
//Set 'Finished' message here
//Enable UI here
}
private async Task CallOperation()
{
int x, y, z; //These get set to something here...
await ExecuteOperation("Operation1", () => OperationWithParams(x, y, z));
}
You most likely also want to add some exception handling in your ExecuteOperation wrapper if you have standard exceptions that your various operations can throw and which should result in UI feedback of some sort.
On a side note, I reordered the name and the action, as this makes it somewhat cleaner (IMO) to pass an anonymous method as the action.
You can pass methods into methods, so to speak, but the delegates have to match. If you have methods with different signatures, you're angling the wrong way.
The Action and Func delegates are generic. There's one to match almost any signature (up to 16 parameters), but again, they have to match the method signature. If you have one method with one parameter, and another with two, or two with different types of parameters, you can't pass those into the same delegate.
So, really it depends on how similar your methods are. If they have varied types of parameters, you'd probably have to "wrap" these calls.
Simplified example:
void Main()
{
List<Action> actions = new List<Action>
{
() => Method1("myString"),
() => Method2("myString2", "myString3")
};
foreach(var action in actions) InvokeAction(action);
}
void InvokeAction(Action action)
{
action();
}
void Method1(string x)
{
Console.WriteLine(x);
}
void Method2(string y, string z)
{
Console.WriteLine(y);
Console.WriteLine(z);
}
On the other hand, if your methods have the same signature, it's a bit simpler:
void Main()
{
InvokeAction(Method1, "myString");
InvokeAction(Method2, "myString2");
}
void InvokeAction(Action<string> action, string param)
{
action(param);
}
void Method1(string x)
{
Console.WriteLine(x);
}
void Method2(string y)
{
Console.WriteLine(y);
}
Now, as to running that asynchronously, it's as simple as using a System.Threading.Task, if you're on .NET 4.0. You could alter my example method as such:
void InvokeAction(Action<string> action, string param)
{
Task.Factory.StartNew(() => action(param));
}
How about something like this (non async/await - version):
void Foo<T>(Action<T> action, string message)
{
MethodWhichMakesMyInterfaceReadOnlyAndSetsMessage(message);
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += (obj, arg) => action.Invoke();
worker.RunWorkerCompleted +=
(obj, arg) =>
{
MethodWhichMakesMyInterfaceReadWrite();
};
worker.RunWorkerAsync();
}
I wrote this before I realised you wanted async/await and tasks specifically - someone else has answered with that however. You can create whatever overloads you want for the extra params for your action.

Check if Action is async lambda

Since I can define an Action as
Action a = async () => { };
Can I somehow determine (at run time) whether the action a is async or not?
No - at least not sensibly. async is just a source code annotation to tell the C# compiler that you really want an asynchronous function/anonymous function.
You could fetch the MethodInfo for the delegate and check whether it has an appropriate attribute applied to it. I personally wouldn't though - the need to know is a design smell. In particular, consider what would happen if you refactored most of the code out of the lambda expression into another method, then used:
Action a = () => CallMethodAsync();
At that point you don't have an async lambda, but the semantics would be the same. Why would you want any code using the delegate to behave differently?
EDIT: This code appears to work, but I would strongly recommend against it:
using System;
using System.Runtime.CompilerServices;
class Test
{
static void Main()
{
Console.WriteLine(IsThisAsync(() => {})); // False
Console.WriteLine(IsThisAsync(async () => {})); // True
}
static bool IsThisAsync(Action action)
{
return action.Method.IsDefined(typeof(AsyncStateMachineAttribute),
false);
}
}
Of course, You can do that.
private static bool IsAsyncAppliedToDelegate(Delegate d)
{
return d.Method.GetCustomAttribute(typeof(AsyncStateMachineAttribute)) != null;
}
If you're looking to build some logic, based on whether a sync or async lanbda has been passed to your method - just introduce overloads.
public void MyMethod(Action action)
{
DoStuff();
}
public void MyMethod(Func<Task> asyncAction)
{
DoOtherStuff();
}

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.

Categories

Resources